【问题标题】:piping output of process to sh while loop?将进程的输出管道传输到 sh while 循环?
【发布时间】:2014-11-13 15:42:15
【问题描述】:

我正在尝试在while 循环中逐行循环遍历 Perl 进程的输出。但是,我在语法上遇到了困难。

我试过这个,但得到一个“不明确的重定向”错误:

#!/bin/sh

while read line; do 
    echo "$line" 
    # do stuff with $line 
done < $(perl process.pl)

./script.sh : line 6: $(perl process.pl): ambiguous redirect

例如,一种(低效)解决方案是:

#!/bin/sh

tmpFile=/tmp/tmpFile.txt
perl process.pl > $tmpFile 
while read line; do 
    echo "$line" 
    # do stuff with $line 
done < $tmpFile

我知道我可以将 Perl 进程通过管道传递到 while 循环:

perl process.pl | while ...

但是while循环是在子shell中执行的,我需要在while循环中设置一些变量在循环完成后保留,所以这不是一个选项。

我能做什么?

【问题讨论】:

    标签: while-loop sh


    【解决方案1】:

    你快到了。试试这个:

    while read -r line; do 
        echo "$line" 
        # do stuff with $line 
    done < <(perl process.pl)
    

    唯一的区别是&lt; 而不是$

    $(cmd) 是一个命令替换,它扩展为括号内命令的输出。另一方面,&lt;(cmd)process substitution。请注意,这是一个 Bash 扩展,因此如果您想使用此方法,还应该将 shebang 更改为 #!/bin/bash

    或者,如果你不使用 Bash,你可以简单地使用管道来代替:

    perl process.pl | while read -r line; do 
        echo "$line" 
        # do stuff with $line 
    done
    

    顺便说一句,you almost always want to use the -r switch with read

    【讨论】:

    • OP 的 shebang 是 #!/bin/sh... 但 OP 提到了 Bash 并标记了问题 Bash... 令人困惑(尤其是进程替换是针对 Bash 而不是 POSIX shell)。
    • 实际上,“管道”解决方案是我想出的第一件事。但是,这会在子 shell 中执行该过程,并且我会丢失在 # do stuff with $line 中修改的所有变量
    • @asf107 我不确定您所说的“我失去了所发生的一切”是什么意思。如果你愿意,你可以重定向循环的输出?
    • 如果你使用的是足够新版本的bash(4.2或更高版本),你可以执行shopt -s lastpipe,管道版本中的while循环将在当前shell中执行,而不是subshel​​l,保留在循环体中所做的任何变量更改。
    • @TomFenech 假设 while 循环的主体有一行 linecount=$((linecount + 1))。如果在子 shell 中执行 while 循环,对此变量的任何更改都将丢失。
    【解决方案2】:

    使用命名管道; bash 进程替换本质上是围绕这一点的语法糖。

    mkfifo output
    perl process.pl > output &
    while IFS= read -r line; do 
        echo "$line" 
        # do stuff with $line 
    done < output
    rm output
    

    命名管道不需要在while 循环开始使用输出之前完成process.pl

    【讨论】:

    • 有趣,我什至不知道有这样的东西存在 :) 谢谢!
    【解决方案3】:

    使用here-document

    while IFS= read -r line; do
        echo "$line" 
        # do stuff with $line 
    done <<EOF
    $(perl process.pl)
    EOF
    

    【讨论】:

      猜你喜欢
      • 2018-01-25
      • 2019-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-28
      相关资源
      最近更新 更多