While 循环只处理 ssh 命令的第一项

Lud*_*vig 4 ssh bash

所以我对 bash 了解不多,需要一些专业人士的帮助。我正在尝试运行这样的脚本:

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

我想要制作的是一个脚本,它遍历文件 1 中的所有地址,以查看它们上次重新启动的时间,然后是文件 2 中的答案。

问题是它只通过第一个地址而不是另一个。

第一个地址有一个密码,我需要输入才能继续该过程。这可能是问题,还是我指定了 file1 中的每一行,还是我一开始就做错了?

pa4*_*080 6

最后我认为,脚本的其余部分没问题。然后我遵循@dessert 的评论并使用shellcheck它引导我解决实际问题及其解决方案:

SC2095:添加< /dev/null以防止 ssh 吞下 stdin。

所以你必须以这种方式改变你的脚本:

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

根据原始答案并感谢@EliahKagan@rexkogitans在评论中提供的有用建议,完整的脚本可能如下所示:

ssh -p 2222 "$p" 'who -b' < /dev/null | awk '{print $(NF-1)" "$NF}' >> 'file2'
Run Code Online (Sandbox Code Playgroud)
  • < /dev/null/由命令的-n选项替换ssh。来自man ssh

    #!/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"
    
    Run Code Online (Sandbox Code Playgroud)
  • 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-indication.txt ) 文件的默认值:

    -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.
    
    Run Code Online (Sandbox Code Playgroud)
  • 为输出文件设置自定义值;也为输入文件设置自定义值:

    ./ssh-check.sh
    
    Run Code Online (Sandbox Code Playgroud)

阅读此答案以了解如何改进整个方法。

  • 除了 `&lt; /dev/null`,您还可以使用 `ssh -n`。这与每个`man` 相同。 (3认同)

rav*_*ery 5

您忘记关闭 while-do 循环。添加done到最后。

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