0

In this example, I have a directory of 2 PNG files:

% ls test_folder
1.png 2.png

Listing all PNG files within the directory works:

% echo test_folder/*.png
test_folder/1.png test_folder/2.png

However, checking if a directory contains any PNG file always returns false.

% if [[ -f test_folder/*.png ]]; then echo 'found'; else echo 'not found'; fi
not found

I've been told by this guide that this would work. Where did I go wrong? And please excuse my limited understanding of Bash.

Hendra Anggrian
  • 5,780
  • 13
  • 57
  • 97
  • `[[ -f *.png ]]` will return true if you have a file named `*.png`. It does not do any globbing. From the bash man page: "Word splitting and pathname expansion are not performed on the words between the [[ and ]]" – William Pursell Aug 06 '22 at 13:27
  • As to "Where did I go wrong?" The page you refer to is suggesting the use of `[`, which is different than `[[`. However, `[ -f *.png ]` is also not the correct way to test for the existence of names that end in ".png", and that test will only work if there is no more than one name that matches. – William Pursell Aug 06 '22 at 13:30
  • IMHO, `-f`|`-e` does not work with `glob`. See shell check specification and solution: https://github.com/koalaman/shellcheck/wiki/SC2144 – Kiran Parajuli Aug 06 '22 at 13:33
  • 1
    This is [BashFAQ #4](https://mywiki.wooledge.org/BashFAQ/004). – Charles Duffy Aug 06 '22 at 13:39

1 Answers1

2

Explained in bash manual:

[[ expression ]] Return a status of 0 or 1 depending on the evaluation of the conditional expression expression. Expressions are composed of the primaries described below under CONDITIONAL EXPRESSIONS. Word splitting and pathname expansion are not performed on the words between the [[ and ]]; tilde expansion, parameter and variable expansion, arithmetic expansion, command substitution, process substitution, and quote removal are performed. Conditional operators such as -f must be unquoted to be recognized as primaries.

Instead you could use an array and check the count:

shopt -s nullglob #  prevents non-matching glob expanding to itself
                  #  can enable later if you prefer to keep that behaviour

pngs=(test_folder/*.png)

if [[ ${#pngs[@]} -gt 0 ]] ; then echo 'found'; else echo 'not found'; fi
P.P
  • 117,907
  • 20
  • 175
  • 238
  • This one works, thanks. But when and how often should we call `shopt -s nullglob`? Always before the array creation or set once and forget? – Hendra Anggrian Aug 06 '22 at 13:47
  • [This answer](https://unix.stackexchange.com/a/204944/72606) explains it. – P.P Aug 06 '22 at 13:51