管道中的循环对Solaris/bin/sh有副作用,但不对Linux有影响

Mel*_*ier 1 linux solaris sh subshell

我在Linux下和solaris下运行相同的脚本.这是脚本:

#!/bin/sh
index=0

ls /tmp | grep e |
while read fileWithE
do
    echo $fileWithE
    index=`expr $index + 1`
done
echo "index is $index"
Run Code Online (Sandbox Code Playgroud)

由于while循环在子shell中运行,我期望'index is 0'作为solaris和linux中的输出.但是在solaris中,$ index是/ tmp下包含'e'的实际文件数.那么虽然循环不在solaris下的子shell中运行?我期待两种操作系统都能得到相同的结果..?

Cha*_*ffy 5

POSIX不要求外壳不运行管道的任何组件; 这是一个留给单个shell作者的实现决策,因此shell可能有任何组件或没有父shell调用的管道组件(因此能够产生超出管道生命周期的副作用)并仍然符合POSIX sh.

已知使用父shell执行管道的最后一个组件的shell包括:

  • ksh88
  • ksh93的
  • zsh的
  • lastpipe禁用作业控制时,启用该选项的bash 4.2 .

如果您想确定在管道中运行的shell命令在所有符合POSIX的shell中没有副作用,那么将整个管道放在显式子shell中是明智的.


您可以通过实验验证行为差异与管道中位置相关的一种方法是通过添加额外的管道元素来稍微修改您的测试.

#!/bin/sh

index=0
ls /tmp \
  | grep e \
  | while read fileWithE; do echo "$fileWithE"; index=`expr $index + 1`; done \
  | cat >/dev/null
echo $index
Run Code Online (Sandbox Code Playgroud)

...你会看到| cat行为的变化,例如循环index所做的更改while在调用shell中不再可见,即使在通常可用的shell上也是如此,否则就是这种情况.