Home > Back-end >  Creating a bash script by calling a command file that contains only linux commands. But it fails wit
Creating a bash script by calling a command file that contains only linux commands. But it fails wit

Time:01-06

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
  •  Tags:  
  • Related