所以我不太了解 bash,需要一些专业帮助。我正在尝试运行如下脚本:
filename='file1'
while read p; do
ssh -p 2222 $p 'who -b' | awk '{print $(NF-1)" "$NF}' >> file2*
我想要编写的是一个脚本,它遍历文件 1 中的所有地址以查看它们上次重新启动的时间,然后在文件 2 中查找答案。
问题是它只通过第一个地址而不通过另一个地址。
第一个地址有密码,我需要输入密码才能继续该过程。这可能是问题所在,还是我指定了 file1 中的每一行,或者我从一开始就做错了?
答案1
最后我假设剧本的其余部分是可以的。然后我跟着@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/
-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
分隔符,并且可以使用反斜杠来转义分隔符(或连续行)。因此read
应该调整命令来读取行。IFS=
改变内部字段分隔符到空字符串,因此我们保留结果中的前导和尾随空格。选项
-r
-raw 输入 - 禁用读取数据中的反斜杠转义和行继续的解释(参考)。printf '%s %s' "$VAR1" "$VAR2"
将提供更好的输出格式(参考)。LANG=C
将保证每个服务器上的输出相同,从而也将保证who -b
输出的解析。awk
注意这里假设有
~/.ssh/config
文件和-p 2222
不需要的附加参数(参考)。
调用上述脚本ssh-check.sh
(不要忘记chmod +x
)并按如下方式使用它:
使用输入的默认值(主机名.txt)和输出(重启指示.txt) 文件:
./ssh-check.sh
为输出文件设置自定义值;也为输入文件设置自定义值:
./ssh-check.sh 'my-custom.out' ./ssh-check.sh 'my-custom.out' 'my-custom.in'
读这个答案看看如何改进整个方法。
答案2
您忘记关闭 while-do 循环。添加done
到末尾。
filename='file1'
while read p; do
ssh -p 2222 $p 'who -b' | awk '{print $(NF-1)" "$NF}' >> file2*
done