Seeing something that is making me question my sanity:
#!/bin/env bash
set -e
for d in '/tmp/somedir/*'; do
for f in "${d}/*pub"; do
echo $f;
done
done
it returns as expected
/tmp/somedir/AAA/fileaa.pub /tmp/somedir/BBB/filebb.pub
But, if I change echo $f
to echo "$f"
or echo "${f}"
I get:
/tmp/somedir/*/*pub
And I am having a hard time understanding why. For starters, it is a single item, so it is not something that is only affecting the echo
line.
using GNU bash, version 5.2.37(1)-release (x86_64-pc-linux-gnu)
here's the shopts on that host
assoc_expand_once off
cdable_vars off
cdspell off
checkhash off
checkjobs off
checkwinsize on
cmdhist on
compat31 off
compat32 off
compat40 off
compat41 off
compat42 off
compat43 off
compat44 off
complete_fullquote on
direxpand off
dirspell off
dotglob off
execfail off
expand_aliases on
extdebug off
extglob on
extquote on
failglob off
force_fignore on
globasciiranges on
globskipdots on
globstar off
gnu_errfmt off
histappend on
histreedit off
histverify off
hostcomplete off
huponexit off
inherit_errexit off
interactive_comments on
lastpipe off
lithist off
localvar_inherit off
localvar_unset off
login_shell off
mailwarn off
no_empty_cmd_completion off
nocaseglob off
nocasematch off
noexpand_translation off
nullglob off
patsub_replacement on
progcomp on
progcomp_alias off
promptvars on
restricted_shell off
shift_verbose off
sourcepath on
varredir_close off
xpg_echo off
#!/bin/env bash
set -e
for d in '/tmp/somedir/*'; do # `*` and `?` should not be quoted unless they exist in the filenames
for f in "${d}/*pub"; do
echo $f; # Here, the variable `f` is actually `/tmp/somedir/*/*pub`
# Without double quotes, Bash will expand the glob at this point
# So, you will see all matching files.
# With double quotes, you will see the original value of var `f`
done
done
After correcting the script:
#!/bin/env bash
set -e
for d in /tmp/somedir/*; do
for f in "${d}"/*pub; do # only quote the variable
echo "$f"; # you will get each filename
done
done
Normally, we should NOT quote *
or ?
in the loop. This way, Bash will expand them to match each filename, and the for loop will behave as expected.