I want to do the following: Read a file line by line and use the line as a parameter.
FILE="cat test"
echo "$FILE" |
while read CMD; do
echo $CMD
done
But when I do echo $CMD
, it just prints cat test
.
I want to do the following: Read a file line by line and use the line as a parameter.
FILE="cat test"
echo "$FILE" |
while read CMD; do
echo $CMD
done
But when I do echo $CMD
, it just prints cat test
.
The best way to do this is to redirect the file into the loop:
# Basic idea. Keep reading for improvements.
FILE=test
while read CMD; do
echo "$CMD"
done < "$FILE"
A redirection with < "$FILE"
has a few advantages over cat "$FILE" | while ...
. It avoids a useless use of cat, saving an unnecessary child process. It also avoids a common pitfall where the loop runs in a subshell. In Bash, commands in a |
pipeline run in subshells, which means variable assignments are lost after the loop ends. Redirection with <
doesn't have that problem, so you could use $CMD
after the loop or modify other variables inside the loop. It also, again, avoids unnecessary child processes.
There are some additional improvements that could be made:
IFS=
so that read
won't trim leading and trailing whitespace from each line.-r
to read
to prevent backslashes from being interpreted as escape sequences.CMD
and FILE
. The Bash convention is that only environmental and internal shell variables are uppercase.printf
in place of echo
which is safer if $cmd
is a string like -n
, which echo
would interpret as a flag.file=test
while IFS= read -r cmd; do
printf '%s
' "$cmd"
done < "$file"