微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Shell 脚本可以逐行读取文件,但不能对每一行执行操作

如何解决Shell 脚本可以逐行读取文件,但不能对每一行执行操作

我正在尝试在多台机器上运行此命令

sshpass -p 'nico' ssh -o 'StrictHostKeyChecking=no' nico@x.x.x.x "mkdir test"

IP 存储在以下 .txt 文件

$ cat ips.txt
10.0.2.15
10.0.2.5

我创建了一个 bash 脚本来逐行读取这个文件。如果我使用 echo 运行它:

#!/bin/bash
input="ips.txt"
while IFS= read -r line
do
  echo "$line"
  #sshpass -p 'nico' ssh -o 'StrictHostKeyChecking=no' nico@$line "mkdir test"
done < "$input"

它打印每一行:

$ ./variables.sh
10.0.2.15
10.0.2.5

这让我明白脚本正在按预期工作。但是,当我用我想为每一行运行的命令替换 echo 行时:

#!/bin/bash
    input="ips.txt"
    while IFS= read -r line
    do
      #echo "$line"
      sshpass -p 'nico' ssh -o 'StrictHostKeyChecking=no' nico@$line "mkdir test"
    done < "$input"

它只对文件的第一个 IP 执行操作,然后停止。为什么?

解决方法

通过使用 for 而不是 while 设法解决了这个问题。脚本最终看起来像这样:

for file in $(cat ips.txt)
do
  sshpass -p 'nico' ssh -o 'StrictHostKeyChecking=no' nico@$file "mkdir test"
done
,

虽然你的例子是一个有效的解决方案,但它不是解释。

你可以在这里找到解释:ssh breaks out of while-loop in bash

两个字:

  1. "while" 循环继续从循环标头中定义的相同文件描述符(在您的情况下为 $input )中读取
  2. ssh(或 sshpass)从标准输入读取数据(但在你的情况下是从文件描述符 $input)。这是隐藏内容的关键,因为我们没有执行“ssh”来读取数据。

只是为了理解这个问题,您可能会遇到同样奇怪的经历,例如在 while 循环中使用“ffmpeg”或“mplayer”等命令。 Mplayer 和 ffmpeg 在运行时使用键盘,因此它们将消耗所有文件描述符。

另一个有趣而有趣的例子:

#!/bin/bash

{
  echo first
  for ((i=0; i < 16384; i++)); do echo "testing"; done
  echo "second"
} > test_file

while IFS= read -r line
do
  echo "Read $line"
  cat | uptime > /dev/null
done < test_file

在第一部分我们写第一行:第一 16384 行:测试 然后最后一行:第二个

16384 行“测试”等于 128Kb 缓冲区

在第二部分,命令“cat | uptime”将消耗恰好 128Kb 的缓冲区,因此我们的脚本将给出

Read first
Read second

作为解决方案,正如您所做的那样,我们可以使用“for”循环。 或者使用“ssh -n” 或者使用一些文件描述符 - 您可以在我提供的链接中找到示例。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。