而管道中的循环对Solaris/bin/sh有副作用,但对Linux没有副作用

而管道中的循环对Solaris/bin/sh有副作用,但对Linux没有副作用,linux,sh,solaris,subshell,Linux,Sh,Solaris,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" 由于while循环在子shell中运行,所以在solaris和linux中,我希望“index是0”作为输出。 但在solaris中,$index是/tmp下

我在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"
由于while循环在子shell中运行,所以在solaris和linux中,我希望“index是0”作为输出。 但在solaris中,$index是/tmp下包含“e”的文件的实际数量。 那么,虽然循环不会在solaris下的子shell中运行?我在两个操作系统中都期望得到相同的结果。

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

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

  • ksh88
  • ksh93
  • zsh
  • 禁用作业控制时,bash 4.2启用了
    lastpipe
    选项
如果您想确保在管道中运行的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
…您将看到,
|cat
更改了行为,例如
索引所做的更改,而
循环在调用shell中不再可见,即使在通常可用的shell上也是如此;这是一个留给单个shell作者的实现决策,因此shell可能有父shell调用的管道的任何组件或没有组件(因此能够产生在管道生命周期之外持续存在的副作用),并且仍然符合POSIX sh

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

  • ksh88
  • ksh93
  • zsh
  • 禁用作业控制时,bash 4.2启用了
    lastpipe
    选项
如果您想确保在管道中运行的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

…您将看到,
| cat
更改了行为,例如
索引所做的更改,而
循环在调用shell中不再可见,即使在通常可用的shell上也是如此。

不确定这是一个问题还是一个注释,对吧,修复了,谢谢…顺便说一句,如果您真的想用
e
s来迭代文件,那么*e*
中的
for fileWithE就不那么容易出错。另请参阅,谢谢,这只是出于问题的目的..不是真的在查找包含“e”的文件,但感谢注意/bin/sh是Solaris 10及更高版本上的古老Bourne shell,但在Solaris 11上是ksh93,因此您使用哪个版本可能会更改结果。不确定这是一个问题还是一个注释对,修复了此问题,谢谢…顺便说一句,如果您真的想用
e
s来迭代文件,那么*e*
中的
for fileWithE就不那么容易出错。另请参阅,谢谢,这只是为了回答问题。.并非真正查找包含“e”的文件,但感谢注意/bin/sh是Solaris 10及更高版本上的古老Bourne shell,但在Solaris 11上是ksh93,因此您使用的版本可能会更改结果。关于一个shell,可能包含第一个组件,最后一个组件,或者父shell调用的管道中没有任何组件:POSIX实际上允许在父shell中执行任何或所有组件,尽管后者很难实现,或者父shell调用的管道中没有任何组件:POSIX实际上允许在父shell中执行任何或所有组件,尽管后者很难实现。