Цикл while обрабатывает только первую запись команды ssh
Так что я не очень разбираюсь в bash и нуждаюсь в профессиональной помощи. Я пытаюсь запустить скрипт как этот:
filename='file1'
while read p; do
ssh -p 2222 $p 'who -b' | awk '{print $(NF-1)" "$NF}' >> file2*
я пытаюсь создать скрипт, который просматривает все адреса в файле1, чтобы увидеть, когда они в последний раз перезагружаются, а затем - ответ в файле2.
Проблема в том, что он проходит только по первому адресу, а не по другому.
Первый адрес получил пароль, который мне нужно ввести, чтобы продолжить процесс. Может ли это быть проблемой, или я указываю каждую строку в file1, или я делаю абсолютно неправильно с самого начала?
2 ответа
Наконец я предположил, что остальная часть сценария в порядке. Затем я последовал комментарию @ десерт и использовал shellcheck что привело меня к актуальной проблеме и ее решению:
SC2095: добавить
< /dev/nullчтобы предотвратить ssh от глотания стандартного ввода.
Таким образом, вы должны изменить свой скрипт следующим образом:
ssh -p 2222 "$p" 'who -b' < /dev/null | awk '{print $(NF-1)" "$NF}' >> 'file2'
Согласно первоначальному ответу и благодаря полезным советам, предоставленным в комментариях @EliahKagan и @rexkogitans, полный сценарий может выглядеть так:
#!/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/заменяется-nвариантsshкоманда. От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- как говорит @StéphaneChazelas в своем энциклопедическом ответе - это канонический способ прочитать одну строку ввода с помощьюreadвстроенныйКлюч в том, что
readчитает слова из строки (возможно, с обратной косой чертой), где слова$IFSdelimited и backslash могут использоваться для экранирования (или продолжения строк). ИтакreadКоманда должна быть настроена на чтение строк.IFS=изменяет внутренний разделитель полей на пустую строку, таким образом мы сохраняем начальные и конечные пробелы в результате.Опция
-r- r aw input - отключает интерпретацию обратной косой черты и продолжения строки в прочитанных данных ( ссылка).
printf '%s %s' "$VAR1" "$VAR2"обеспечит лучший выходной формат ( ссылка).LANG=Cбудет гарантировать идентичный выходwho -bна каждом сервере, таким образом, анализ выходных данных сawkбудет гарантировано.Примечание здесь предполагается, что есть
~/.ssh/configфайл и дополнительные параметры как-p 2222не нужны ( ссылка).
Вызовите вышеупомянутый сценарий ssh-check.sh (не забудьте chmod +x) и использовать его следующим образом:
Используйте значения по умолчанию для входных (hosts.txt) и выходных (reboot- display.txt) файлов:
./ssh-check.shУстановить пользовательское значение для выходного файла; установить пользовательское значение также для входных файлов:
./ssh-check.sh 'my-custom.out' ./ssh-check.sh 'my-custom.out' 'my-custom.in'
Прочтите этот ответ, чтобы увидеть, как можно улучшить весь подход.
Вы забыли закрыть цикл while-do. добавлять done к концу.
filename='file1'
while read p; do
ssh -p 2222 $p 'who -b' | awk '{print $(NF-1)" "$NF}' >> file2*
done