while循环只处理ssh命令的第一个条目
所以我对bash不太了解,需要一些亲的帮助。 我正在尝试运行像这样的脚本:
filename='file1' while read p; do ssh -p 2222 $p 'who -b' | awk '{print $(NF-1)" "$NF}' >> file2*
我想要做的是一个脚本,它遍历file1中的所有地址,以查看它们上次重新启动的时间,然后是file2中的答案。
问题是它只通过第一个地址而不是另一个地址。
第一个地址获得了我需要键入的密码以继续该过程。 可能这是问题,还是我在file1中指定了每一行,或者我开始时做的绝对错误?
最后我假设,脚本的其余部分没问题。 然后我跟着@ dessert的评论并使用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/
由ssh
命令的-n
选项替换。 来自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
builtin读取一行输入的规范方法 。-
关键是读取来自(可能是反斜杠 - 续)行的单词,其中单词是
$IFS
分隔,反斜杠可用于转义分隔符(或继续行)。 所以应该调整read
命令来读取行。 -
IFS=
将内部字段分隔符更改为空字符串 ,因此我们在结果中保留前导和尾随空格。 -
选项
-r
- r aw输入 - 禁用读取数据( 引用 )中反斜杠转义和行继续的解释。
-
-
printf '%s %s' "$VAR1" "$VAR2"
将提供更好的输出格式( 参考 )。 -
LANG=C
将保证每个服务器上who -b
输出相同,因此也可以保证使用awk
解析输出。 -
注意这里假设有
~/.ssh/config
文件和不需要-p 2222
附加参数( 参考 )。
调用上面的ssh-check.sh
(不要忘记chmod +x
)并以这种方式使用它:
-
使用输入( hosts.txt )和输出( reboot-indication.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