I tried to do something tricky today with bash scripting, which made me question my knowledge of bash scripting.
I have the following script called get_ftypes.sh
, where the first input argument is a file containing file globs:
for ftype in `cat $1`
do
echo "this is ftype $ftype"
done
For example, the script would be called like this get_ftypes.sh file_types
, and file_types
would contain something like this:
*.txt
*.sh
I would expect the echo
to print each line in the file, which in this example would be *.txt
, *.sh
, etc. But, instead it expands the globbing, *
, and it echos the actual file names, instead of the globb as I would expect.
Any reason for this behavior? I cannot figure out why. Thank you.
On the line for ftype in `cat $1`
, the shell performs both word splitting and pathname expansion. If you don't want that, use a while
loop:
while read -r ftype
do
echo "this is ftype $ftype"
done <"$1"
This loop reads one line at a time from the file $1
and, while leading and trailing whitespace are removed from each line, no expansions are performed.
(If you want to keep the leading and trailing whitespace, use while IFS= read -r ftype
).
Typically, for
loops are useful when you are looping over items that are already shell-defined variables, like for x in "$@"
. If you are reading something in from an external command or file, you typically want a while read
loop.
When processing files line-by-line, the goal can often be accomplished more efficiently using sed or awk. As an example using awk, the above loop simplifies to:
$ awk '{print "this is ftype " $0}' filetypes
this is ftype *.txt
this is ftype *.sh