0

I want to echo files that does not contain a substring "cds" or "rna" in their filenames.

I use the following code:

for genome in *
do
if [ ! "$genome" == *"cds"* ] || [ ! "$genome" == *"rna"* ]
then
    echo $genome
fi
done

The code does not return any error but it keeps printing files that have the substrings indicated in the file name. How can I correct this? Thank you!

Homap
  • 2,142
  • 5
  • 24
  • 34
  • In this test, you want `&&` rather than `||`, because you want filenames that don't contain "cds" *and also* don't contain "rna". See ["Why does non-equality check of one variable against many values always return true?"](https://stackoverflow.com/questions/26337003/why-does-non-equality-check-of-one-variable-against-many-values-always-return-tr) Also, read about [De Morgan's laws](https://en.wikipedia.org/wiki/De_Morgan%27s_laws) for how to combine negative tests. – Gordon Davisson Dec 01 '22 at 11:19
  • The `*` does not act as a wildcard pattern match (as you can verify with `[ c == c* ] && echo true`. Aside from this, the logic itself is broken, as you try to find names which either don't contain cds or don't contain rna (i.e. you try to exclude those which contain both _cds_ and _rna_). – user1934428 Dec 01 '22 at 11:20

2 Answers2

1

The condition should be written as

[[ ! $genome =~ cds|rna ]] && echo $genome
user1934428
  • 19,864
  • 7
  • 42
  • 87
1

There's two separate mistakes:

  • When using * in Bash comparisons, you need to use two sets of brackets, so [ ... ] should be [[ ... ]].
  • I think you really mean "files that does not contain a substring "cds" and also not "rna" in their filenames. That is, the 'or' (||) should be an 'and' (&&).
for genome in *
do
if [[ ! "$genome" == *"cds"* ]] && [[ ! "$genome" == *"rna"* ]]
then
    echo $genome
fi
done
jmd_dk
  • 12,125
  • 9
  • 63
  • 94