Цикл 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
читает слова из строки (возможно, с обратной косой чертой), где слова$IFS
delimited и 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