For simplicity I removed all command and just using one command "ip addr"
admin@danec>cat commandfile.txt
ip addr
admin@danec> cat script.sh
IFS=$'\n'
COMMAND=/tmp/commandfile.txt
for command in `cat $COMMAND`
do
{
echo $command
$command
}
done
admin@danec>./script.sh
ip addr
./script.sh: line 7: ip addr: command not found
There is no issue of path because when I copy the command "ip addr" in separate script file and execute, it works fine. Before answering I will appreciate if you try it first and reproduce the problem. See if you can fix it.
CodePudding user response:
You can do this instead:
#!/bin/bash
readarray -t commands < /tmp/commandfile.txt
for cmd in "${commands[@]}"; do
echo "$cmd"
eval "$cmd" || break
done
The error you had is caused by IFS being set to $'\n' which prevent word splitting from splitting command arguments. Better rely on readarray and explicit eval since that's what you want to do.
As for whether this is safe, it's another topic.
CodePudding user response:
Not sure what the context is, but maybe just
. /tmp/commandfile.txt
?
CodePudding user response:
Like @konsolebox mentioned, the issue is due to your IFS variable. When wordsplitting occcurs, it only wordsplits between newlines. This means that when you try to do $command, it doesn't see ip addr as two words: only 1 word (as below)
$ "ip addr"
bash: ip addr: command not found
To solve this without using eval, you can simply set the IFS to the default value after you do $(cat "$COMMAND"). Of course, a more elegant solution would be using indexed arrays and the readarray builtin, but if it is for something quick, the below solution works just fine
IFS=$'\n'
COMMAND=/tmp/commandfile.txt
for command in $(cat "$COMMAND"); do
IFS=$' \t\n'
echo $command
$command
done
And also, a little tip, you don't have to use cat if you construct the for loop as such:
for command in $(<"$COMMAND"); do
