While 循环仅处理 ssh 命令的第一个条目

While 循环仅处理 ssh 命令的第一个条目

所以我不太了解 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

相关内容