While loop only processes the first entry of ssh command
So I don't know much about bash and need some pro help. I am trying to run a script like this one:
filename='file1'
while read p; do
ssh -p 2222 $p 'who -b' | awk '{print $(NF-1)" "$NF}' >> file2*what I am trying to make is a script that go through all addresses in file1 to see when they last rebooted and then but the answer in file2.
The problem is that it only go through the first address and not the other.
The first address got a password I need to type to proceed the process. May this be the problem or do I specify every line in file1 or am I doing absolutely wrong to begin with?
22 Answers
Finally I assumed that, the rest part of the script is okay. Then I followed @dessert's comment and used shellcheck that lead me to the actual issue and its solution:
SC2095: Add
< /dev/nullto prevent ssh from swallowing stdin.
So you have to change your script in this way:
ssh -p 2222 "$p" 'who -b' < /dev/null | awk '{print $(NF-1)" "$NF}' >> 'file2'According to the original answer and thanks to the useful advises, provided in the comments by @EliahKagan and @rexkogitans, the complete script could look as this:
#!/bin/bash
# Collect the user's input, and if it`s empty set the default values
[[ -z "${1}" ]] && OUT_FILE="reboot-indication.txt" || OUT_FILE="$1"
[[ -z "${2}" ]] && IN_FILE="hosts.txt" || IN_FILE="$2"
while IFS= read -r host; do indication="$(ssh -n "$host" 'LANG=C who -b' | awk '{print $(NF-1)" "$NF}')" printf '%-14s %s\n' "$host" "$indication" >> "$OUT_FILE"
done < "$IN_FILE"< /dev/null/is replaced by the-noption of thesshcommand. Fromman ssh:-n Redirects stdin from /dev/null (actually, prevents reading from stdin). This must be used when ssh is run in the background... This does not work if ssh needs to ask for a password or passphrase; see also the -f option.IFS= read -r line- as @StéphaneChazelas says in his encyclopedic answer - is the canonical way to read one line of input with thereadbuiltin.The key is that
readreads words from a (possibly backslash-continued) line, where words are$IFSdelimited and backslash can be used to escape the delimiters (or continue lines). So thereadcommand should be tweaked to read lines.IFS=changes the internal field separator to the null string, thus we preserve leading and trailing whitespace in the result.The option
-r- raw input - disables interpretation of backslash escapes and line-continuation in the read data (reference).printf '%s %s' "$VAR1" "$VAR2"will provide a better output format (reference).LANG=Cwill guarantee identical output ofwho -bon each server, thus the parsing of the output withawkwill be guaranteed as well.Note here is assumed there is
~/.ssh/configfile and additional parameters as-p 2222are not needed (reference).
Call the above scrip ssh-check.sh (don't forget to chmod +x) and use it in this way:
Use the default values of the input (hosts.txt) and the output (reboot-indication.txt) files:
./ssh-check.shSet custom value for the output file; set custom value also for the input files:
./ssh-check.sh 'my-custom.out' ./ssh-check.sh 'my-custom.out' 'my-custom.in'
Read this answer to see how the entire approach could be improved.
2You forgot to close the while-do loop. Add done to the end.
filename='file1'
while read p; do ssh -p 2222 $p 'who -b' | awk '{print $(NF-1)" "$NF}' >> file2*
done