【问题标题】:Why does this while stop after first iteration? [duplicate]为什么这在第一次迭代后会停止? [复制]
【发布时间】:2023-10-11 06:38:02
【问题描述】:

如果我执行以下操作

tr -cd 'a-z' < /dev/urandom | fold -w10 | head -n40 > pw
for f in $(seq -w 40); do echo linux$f.example.com;done > hosts

while read -r x && read -r y <&3; do ssh $x -l root echo $y;done <hosts 3<pw 

然后循环在第一次迭代后停止,但如果我插入一个echo(这不是我想要的),那么它会循环遍历所有 40 个。

while read -r x && read -r y <&3; do echo ssh $x -l root echo $y;done <hosts 3<pw 

问题

如何让它执行所有 40 次迭代,而不先创建临时文件?

【问题讨论】:

  • 也许告诉我们它应该做什么,因为它不起作用!
  • 我想知道ssh 是否正在窃取您的 fds 并读取/刷新它们。尝试为ssh 命令关闭标准输入和&amp;3
  • @EtanReisner 添加&lt;/dev/null 2&gt;/dev/null 解决了这个问题。谢谢=)

标签: linux bash ssh


【解决方案1】:

这似乎是ssh 正在查看并耗尽您的 fds。

运行时关闭fds到ssh

【讨论】:

    【解决方案2】:

    如何避免临时文件...

    #!/bin/bash
    h=1
    LC_CTYPE="C" tr -cd 'a-z' < /dev/urandom | fold -w10 | head -n40 | \
       while read x; do
          host=$(printf "linux%02d.example.com" $h)
          echo $x $host
          ((h++))
       done
    

    另一种避免临时文件的方法是使用进程替换来生成您需要的两个输入,然后将它们成对粘贴到单独的行上,然后在一个循环中读取它们,如下所示:

    #!/bin/bash
    paste \
       <(LC_CTYPE="C" tr -cd 'a-z' < /dev/urandom | fold -w10)        \
       <(for f in $(seq -w 40); do echo linux$f.example.com;done) |   \
       head -n40 | while read x y; do
          echo $x $y
       done
    

    如果您担心子shell 中的变量,也可以反过来做:

    #!/bin/bash
    while read x y; do
       echo $x $y
    done < <( paste \
               <(LC_CTYPE="C" tr -cd 'a-z' < /dev/urandom | fold -w10)        \
               <(for f in $(seq -w 40); do echo linux$f.example.com;done) |   \
               head -n40)
    

    【讨论】:

    • 使用管道隐含的子shell使h计数器无法正常工作。
    • @EtanReisner 好的,谢谢。我会在早上检查 - 虽然我确实在我的 Mac 上运行过它并且它看起来是正确的。
    • @EtanReisner 它似乎在我的机器上运行良好。只涉及一个子shell,它处理while 循环。它在启动时从其父级继承h,然后在每次循环中愉快地递增它。我看不出有任何问题 - 你能解释一下你的意思吗?
    • 啊,抱歉,我错过了 h 仅在这种情况下供子外壳使用,而不是跨各种子外壳携带。 (虽然我相信该管道中实际上涉及三到四个子外壳,但管道的每个部分都有一个,尽管可能不会至少有一个部分使用当前外壳。)