Цикл while обрабатывает только первую запись команды ssh

Так что я не очень разбираюсь в bash и нуждаюсь в профессиональной помощи. Я пытаюсь запустить скрипт, подобный этому:

filename='file1'
while read p; do
ssh -p 2222 $p 'who -b' | awk '{print $(NF-1)" "$NF}' >> file2*

я пытаюсь создать скрипт, который просматривает все адреса в файле1, чтобы увидеть, когда они в последний раз перезагружаются, а затем - ответ в файле2.

Проблема в том, что он проходит только по первому адресу, а не по другому.

Первый адрес получил пароль, который мне нужно ввести, чтобы продолжить процесс. Может ли это быть проблемой, или я указываю каждую строку в file1, или я делаю абсолютно неправильно с самого начала?

3
задан 1 December 2017 в 19:00

2 ответа

Наконец я предположил, что остальная часть скрипта в порядке.Затем я следил за @ comment и использовал shellcheck , который привел меня к актуальной проблеме и ее решению:

SC2095 : Добавить , чтобы 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"
  • заменяется параметром -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'
     

Прочтите этот ответ , чтобы увидеть, как можно улучшить весь подход.

5
ответ дан 1 December 2017 в 19:00

Вы забыли закрыть цикл while-do. Добавьте в конец done .

filename='file1'
while read p; do
   ssh -p 2222 $p 'who -b' | awk '{print $(NF-1)" "$NF}' >> file2*
done
5
ответ дан 1 December 2017 в 19:00

Другие вопросы по тегам:

Похожие вопросы: