Так что я не очень разбираюсь в bash и нуждаюсь в профессиональной помощи. Я пытаюсь запустить скрипт, подобный этому:
filename='file1'
while read p; do
ssh -p 2222 $p 'who -b' | awk '{print $(NF-1)" "$NF}' >> file2*
я пытаюсь создать скрипт, который просматривает все адреса в файле1, чтобы увидеть, когда они в последний раз перезагружаются, а затем - ответ в файле2.
Проблема в том, что он проходит только по первому адресу, а не по другому.
Первый адрес получил пароль, который мне нужно ввести, чтобы продолжить процесс. Может ли это быть проблемой, или я указываю каждую строку в file1, или я делаю абсолютно неправильно с самого начала?
Наконец я предположил, что остальная часть скрипта в порядке.Затем я следил за @ comment и использовал shellcheck
, который привел меня к актуальной проблеме и ее решению:
SC2095 : Добавить
dev / null
, чтобы ssh не проглатывал stdin.
Поэтому вам нужно изменить свой скрипт следующим образом:
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 Перенаправляет stdin из / dev / null (фактически, предотвращает чтение из stdin).
Это необходимо использовать, когда ssh работает в фоновом режиме ... Это не работает
если ssh нужно запросить пароль или кодовую фразу; см. также параметр -f.
IFS = read -r line
- как говорит @ StéphaneChazelas в своем энциклопедическом ответе - это канонический способ прочитать одну строку ввода с read
встроенный .
Суть в том, что read
считывает слова из строки (возможно, с обратной косой чертой), где слова разделены $ IFS
, а обратная косая черта может использоваться для выхода из разделителей (или продолжения линий). Поэтому команду 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-indicator.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