捕获管道输出和子壳的副作用

时间:2016-09-17 20:49:47

标签: bash pipe

代码

在示例函数a中,我从管道捕获输入,如下所示:

function a() { 
    if [ -t 1 ]; then 
        read test
        echo "$test"
    fi

    if [[ -z "$1" ]]; then 
        echo "$1"
    fi
}

调用如下:

echo "hey " | a "hello"

产生输出:

hey
hello

问题

我受到了this answer的启发,但是在片段之后引用了我的一句话:

  

但没有意义 - 你的变量任务可能不会持久!管道可以生成子shell,其中环境由值继承,而不是通过引用继承。这就是为什么读取不会对来自管道的输入感到烦恼的原因 - 它是未定义的。

我不确定我是否理解这一点 - 试图创建子壳产生了我预期的输出:

function a() { 
    (
        if [ -t 1 ]; then 
            read test
            echo "$test"
        fi

        if [[ -z "$1" ]]; then 
            echo "$1"
        fi
    )
}

在方法调用中:

(echo "hey") | (a "hello")

仍然产生:

hey
hello

那么你的变量赋值的含义可能不会持久!管道可能会产生子shell,其中环境是通过值继承的,而不是通过引用继承。?有什么东西我误解了吗?

2 个答案:

答案 0 :(得分:1)

试试这个:

echo test | read myvar
echo $myvar

您可能希望它会打印test,但它没有打印,它什么都不打印。原因是bash将在子shell进程中执行read myvar。该变量将被读取,但仅在该子shell中。所以在原始shell中,变量永远不会被设置。

另一方面,如果你这样做:

echo test | { read myvar; echo $myvar; }

或者

echo test | (read myvar; echo $myvar)

您将获得预期的输出。这就是你的代码所发生的事情。

答案 1 :(得分:1)

引用的注释不正确。 read并不关心其输入源自何处。

但是,您必须记住,通过调用read命令分配的变量是执行命令的(子)shell的一部分。

默认情况下,在管道中执行的每个命令(由|分隔的一系列命令)都在单独的子shell中执行。因此,执行echo foo | read foo后,您会发现$foo的值没有改变:不是因为read忽略了它的输入而是因为shell read已不再执行存在。