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

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

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

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

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

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

2
задан 1 December 2017 в 20:00

6 ответов

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

SC2095: Добавьте < /dev/null, чтобы предотвратить ssh от проглатывания stdin.

Итак, вы должны изменить свой сценарий таким образом:

ssh -p 2222 "$p" 'who -b' < /dev/null | awk '{print $(NF-1)" "$NF}' >> 'file2'

Согласно комментарию @ dessert и спасибо в полезные советы, представленные в комментариях @EliahKagan и shellcheck , полный скрипт может выглядеть так:

#!/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/ заменяется на [ f9] команды 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 - как говорит Стефан Чазелас в своем энциклопедическом ответе - это канонический способ чтения одной строки ввода с встроенным read. Ключ состоит в том, что read читает слова из строки (возможно, обратной косой черты), где слова ограничены $IFS и обратная косая черта может использоваться для исключения разделителей (или продолжения строк). Поэтому команда read должна быть изменена для чтения строк. IFS= изменяет внутренний разделитель полей на нулевую строку, таким образом, мы сохраняем в результате начальные и конечные пробелы. Опция -r - необработанный вход - отключает интерпретацию обратных слэшей и продолжения строки в прочитанных данных (ссылка). printf '%s %s' "$VAR1" "$VAR2" обеспечит лучший выходной формат (ссылка). LANG=C гарантирует идентичный вывод who -b на каждом сервере, поэтому будет гарантирован синтаксический анализ вывода с awk. Обратите внимание, что предполагается ~/.ssh/config файл и дополнительные параметры, поскольку -p 2222 не нужны (ссылка).

Вызвать этот скрипт ssh-check.sh (не забудьте chmod +x) и использовать его таким образом:

< /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.

< /dev/null/ заменяется опцией -n команды ssh. Из man ssh:

./ssh-check.sh 'my-custom.out'
./ssh-check.sh 'my-custom.out' 'my-custom.in'

Установить пользовательское значение для выходного файла; установить пользовательское значение также для входных файлов:

5
ответ дан 22 May 2018 в 15:58
  • 1
    Поскольку вы показываете полный скрипт с различными улучшениями, я предлагаю использовать read -r p - это одна из вещей, о которых упоминает ShellCheck, вместо read p. Очень редко кто-то на самом деле хочет read интерпретировать обратные слэш-экраны, а опускать -r, как правило, заставляет читателей (включая автора позже) задаться вопросом, предвидится ли такая необычная ситуация, поэтому read должно быть всегда всегда прошел опцию -r. Кроме того, в то время как в этом случае, вероятно, предполагается зачистка начального и конечного пробелов, вы можете упомянуть о важности не устанавливать IFS= для read. – Eliah Kagan 23 November 2017 в 16:42
  • 2
    Вместо < /dev/null вы также можете использовать ssh -n. Это то же самое, что и в man. – rexkogitans 23 November 2017 в 19:41

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

SC2095: Добавьте < /dev/null, чтобы предотвратить ssh от проглатывания stdin.

Итак, вы должны изменить свой сценарий таким образом:

ssh -p 2222 "$p" 'who -b' < /dev/null | awk '{print $(NF-1)" "$NF}' >> 'file2'

Согласно комментарию @ dessert и спасибо в полезные советы, представленные в комментариях @EliahKagan и shellcheck , полный скрипт может выглядеть так:

#!/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 - как говорит Стефан Чазелас в своем энциклопедическом ответе - это канонический способ чтения одной строки ввода с встроенным read. Ключ состоит в том, что read читает слова из строки (возможно, обратной косой черты), где слова ограничены $IFS и обратная косая черта может использоваться для исключения разделителей (или продолжения строк). Поэтому команда read должна быть изменена для чтения строк. IFS= изменяет внутренний разделитель полей на нулевую строку, таким образом, мы сохраняем в результате начальные и конечные пробелы. Опция -r - необработанный вход - отключает интерпретацию обратных слэшей и продолжения строки в прочитанных данных (ссылка). printf '%s %s' "$VAR1" "$VAR2" обеспечит лучший выходной формат (ссылка). LANG=C гарантирует идентичный вывод who -b на каждом сервере, поэтому будет гарантирован синтаксический анализ вывода с awk. Обратите внимание, что предполагается ~/.ssh/config файл и дополнительные параметры, поскольку -p 2222 не нужны (ссылка).

Вызвать этот скрипт ssh-check.sh (не забудьте chmod +x) и использовать его таким образом:

< /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.

< /dev/null/ заменяется опцией -n команды ssh. Из man ssh:

./ssh-check.sh 'my-custom.out' ./ssh-check.sh 'my-custom.out' 'my-custom.in'

Установить пользовательское значение для выходного файла; установить пользовательское значение также для входных файлов:

5
ответ дан 18 July 2018 в 02:45

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

SC2095: Добавьте < /dev/null, чтобы предотвратить ssh от проглатывания stdin.

Итак, вы должны изменить свой сценарий таким образом:

ssh -p 2222 "$p" 'who -b' < /dev/null | awk '{print $(NF-1)" "$NF}' >> 'file2'

Согласно комментарию @ dessert и спасибо в полезные советы, представленные в комментариях @EliahKagan и shellcheck , полный скрипт может выглядеть так:

#!/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 - как говорит Стефан Чазелас в своем энциклопедическом ответе - это канонический способ чтения одной строки ввода с встроенным read. Ключ состоит в том, что read читает слова из строки (возможно, обратной косой черты), где слова ограничены $IFS и обратная косая черта может использоваться для исключения разделителей (или продолжения строк). Поэтому команда read должна быть изменена для чтения строк. IFS= изменяет внутренний разделитель полей на нулевую строку, таким образом, мы сохраняем в результате начальные и конечные пробелы. Опция -r - необработанный вход - отключает интерпретацию обратных слэшей и продолжения строки в прочитанных данных (ссылка). printf '%s %s' "$VAR1" "$VAR2" обеспечит лучший выходной формат (ссылка). LANG=C гарантирует идентичный вывод who -b на каждом сервере, поэтому будет гарантирован синтаксический анализ вывода с awk. Обратите внимание, что предполагается ~/.ssh/config файл и дополнительные параметры, поскольку -p 2222 не нужны (ссылка).

Вызвать этот скрипт ssh-check.sh (не забудьте chmod +x) и использовать его таким образом:

< /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.

< /dev/null/ заменяется опцией -n команды ssh. Из man ssh:

./ssh-check.sh 'my-custom.out' ./ssh-check.sh 'my-custom.out' 'my-custom.in'

Установить пользовательское значение для выходного файла; установить пользовательское значение также для входных файлов:

5
ответ дан 24 July 2018 в 17:38

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

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

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

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

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

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

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

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