2

The content of 'cmds.txt' is as follow:

ssh -o "StrictHostKeyChecking no" [email protected] "/usr/bin/whoami"
ssh -o "StrictHostKeyChecking no" [email protected] "/usr/bin/whoami"
ssh -o "StrictHostKeyChecking no" [email protected] "/usr/bin/whoami"
ssh -o "StrictHostKeyChecking no" [email protected] "/usr/bin/whoami"
ssh -o "StrictHostKeyChecking no" [email protected] "/usr/bin/whoami"

I'm trying to iterate through this file in prompt and execute them respectively. My command is:

export IFS=$'\n'; for i in `cat cmds.txt`; do $i; done

But it complains bash: ssh -o "StrictHostKeyChecking no" [email protected] "/usr/bin/whoami": No such file or directory.

Is there anything I'm missing? Thanks a lot.

4 Answers 4

4

Don't put entire commands in variables and don't loop over lines with for. The simple and straightforward solution is to factor out only those parameters which actually vary.

while read user_host; do
    ssh -o "StrictHostKeyChecking no" "$user_host".myhost.cn /usr/bin/whoami
done <<'____HERE'
    adamH@K1201
    alexB@K1202
    adamR@K1203
    kevinC@K1204
    rajE@K1205
____HERE
Sign up to request clarification or add additional context in comments.

1 Comment

Nice perspectives and advice. Thanks!
3

Why don't you just use source?

source cmds.txt

Or even shorter:

. cmds.txt

1 Comment

Thanks for the simplest way to achieve what I intend to do. But anyhow, I'm encountering this problem right now, so I'd like to figure it out :]
2

Since you've set IFS to just a newline, when it does word splitting on $i it only splits it at newlines, the spaces are no longer treated as delimiters. So the entire line is taken as the command name, not a command followed by arguments.

But if you fix that, it still won't work, because quotes are not processed after expanding a variable. You need to use eval to put it through all the rules of command parsing.

IFS=$'\n'; for i in `cat cmds.txt`; do eval "$i"; done

But instead of using for and having to set IFS, you could do:

while read -r i; do eval "$i"; done < cmds.txt

5 Comments

To site: 'quotes are not processed after expanding a variable'. What does it mean?
The quotes you have around "StrictHostKeyChecking: no" will not be parsed to keep that as a single argument. The quotes will be kept in the command literally, and the space will split the argument.
Another question, what does '-r' means after read command? I've man read, but could hardly find anything.
It's in the bash man page. It tells it not to treat backslash as an escape character when reading.
@Jahid In this case eval is just doing exactly what source would do. I don't know why he doesn't want to use source -- maybe he wants to log the commands before each one is executed. But any issues with eval would also affect any other method of executing the commands in the file.
0

Putting commands in variables isn't a good idea, but if you want to do it any way, then you can do this:

while IFS= read -r line; do
${line[*]}
done <cmds.txt

Note: Don't use quotes in variable $line ( "$line" or "${line[*]}" ). It won't work for this case.

One way to use your existing code while avoiding using eval might be:

IFS=$'\n'
for i in `cat cmds.txt`; do #use of $(<cmds.txt) is better than `cat cmds.txt`
bash <<EOF
${i[*]} 
EOF
done

Note: using cat and for to read line from file isn't recommended, use while loop instead.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.