Bash 如何在命令之间重复管道输入,直到应用输出条件?

Bash 如何在命令之间重复管道输入,直到应用输出条件?,bash,shell,Bash,Shell,我想创建一个bash脚本,该脚本在两个进程之间重复管道输出,直到输出包含一些特殊字符 考虑以下两个Python脚本: script1.py from sys import stdin for line in stdin.readline(): if line.isdigit(): print int(line) + 3 from sys import stdin for line in stdin.readline(): if line.isdigit():

我想创建一个bash脚本,该脚本在两个进程之间重复管道输出,直到输出包含一些特殊字符

考虑以下两个Python脚本:

script1.py

from sys import stdin
for line in stdin.readline():
    if line.isdigit():
        print int(line) + 3
from sys import stdin
for line in stdin.readline():
    if line.isdigit():
        print int(line) - 1
script2.py

from sys import stdin
for line in stdin.readline():
    if line.isdigit():
        print int(line) + 3
from sys import stdin
for line in stdin.readline():
    if line.isdigit():
        print int(line) - 1
以及下面的执行

$ echo 0|python script1.py|python script2.py|python script1.py|python script2.py 
4
是否可以创建一个Bash脚本,执行这两个脚本并将输出作为输入传递给另一个脚本,直到script1的输出达到某个特定数量


(我不想修改Python脚本,我不是在实际使用它们,它们只是为了演示我想要实现的目标而创建的)。

假设您的Python脚本
script2.py
在一行上只输出一个数字,您希望执行
pythonscript1.py | pythonscript2.py
,直到输出编号为
4
,下面是一种递归方法。它使用递归,因此如果调用过多,您可能会遇到堆栈溢出:

#!/bin/bash

apply_until4() {
   local l
   read l < <(python script1.py | python script2.py)
   if [[ $l = 4 ]]; then
      echo "$l"
      return
   fi
   echo "$l" | apply_until4
}

echo "0" | apply_until4

没有递归的另一种可能性:

#!/bin/bash

apply_until4() {
   local l
   read l
   until [[ $l = 4 ]]; do
      read l < <(echo "$l" | python script1.py | python script2.py)
   done
   echo "$l"
}

echo "0" | apply_until4
语句可以更改为

l=$(python script.py | python script2.py)
l=$(echo "$l" | python script1.py | python script2.py)
同样地

read l < <(echo "$l" | python script1.py | python script2.py)
不同的是,
读取
将丢弃所有前导空格和尾随空格(如果有)


    一种可以防止叉式炸弹的更安全方法:

    function piper {
        read
        if [[ $REPLY == 4 ]]; then
            echo 4
        elif [[ $REPLY =~ ^[[:digit:]]+$ && $REPLY -lt 4 ]]; then
            echo "$REPLY" | python script1.py | python script2.py | piper
        fi
    }
    
    echo 0 | piper
    

    您想要一个双向管道吗?在概念上与我的递归答案没有区别(并且会有相同的缺陷wrt stackoverflows)。你说的更安全是什么意思?是否只是因为您检查组合的输出是由数字组成的单词?还是我错过了什么?我的答案是什么,会制造一个叉子炸弹?(潜在无限循环,是的,叉形炸弹,我没有看到任何)。此外,正则表达式可能是过度杀伤力,一个glob就可以了;你的测试不是错误就是没用。@gniourf\u gniourf我发现
    [[$REPLY-lt 4]]]
    有点效率低下,但我懒得计算它。你能证明为什么它没用吗?关于叉形炸弹,
    echo“$l”| apply__|4
    可以产生无限的次壳层。为什么正则表达式会被过度使用?什么样的精确表达才足够呢?哦,是的,通过更仔细的检查,
    $REPLY=[:digit:]
    似乎就足够了,因为目标不会增加。
    echo“$l”| apply|直到4
    可以产生无限的子shell,当OP给出的玩具脚本的初始条件错误时,我的回答的目的是展示可以用来实现OP所达到的目标的概念,而不是围绕一个明显的演示案例来设计一个100%的防弹脚本。话虽如此,我们讨论的其他问题变得无关紧要。不过,有两件事:
    [$REPLY=+([[:digit:]])]
    来避免正则表达式;这个安全防护装置使我无法用负数初始化:
    [$REPLY=?(-)+([[:digit:]])]]
    这就是我这么做的明显原因。为了避免可能的分叉炸弹,以防OP错误地发送错误的初始输入。如果要检查glob模式,还需要
    =
    而不仅仅是
    =
    。由于还使用扩展模式,因此需要初始化
    extglob
    。我总是喜欢ext.glob,并对它进行了第一次模式检查,但我只是选择使用正则表达式来减少行数并防止多余的shopt调用。