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/null
to 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 -n
option of the ssh
command. From man 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 the read
builtin.
The key is that read
reads words from a (possibly backslash-continued) line, where words are $IFS
delimited and backslash can be used to escape the delimiters (or continue lines). So the read
command 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=C
will guarantee identical output of who -b
on each server, thus the parsing of the output with awk
will be guaranteed as well.
Note here is assumed there is ~/.ssh/config
file and additional parameters as -p 2222
are 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.sh
Set 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.
#!/bin/bash
as the first line. Also, what exactly do you wantread
to read? If it'sfilename
then adddone <"$filename"
.