管道中的 while 循环对 Solaris /bin/sh 但不是 Linux 有副作用

while loop in pipeline having side effects on Solaris /bin/sh but not Linux

我在 运行 在 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"

自从子 shell 中的 while 循环 运行s 以来,我期望 'index is 0' 作为 solaris 和 linux 中的输出。 但在 solaris 中,$index 是 /tmp 下包含 'e' 的实际文件数。 那么 while 循环不会在 solaris 下的子 shell 中 运行 吗?我在 OS..?

中期待相同的结果

POSIX 不 要求 管道的任何组件都不会被外部 shell 运行;这是留给个人 shell 的作者的实现决定,因此 shell 可能具有父级 shell 调用的管道的任何组件或没有组件(因此能够有副作用持续到管道的生命周期之外)并且仍然符合 POSIX sh.

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

  • ksh88
  • ksh93
  • zsh
  • bash 4.2 启用 lastpipe 选项,禁用作业控制。

如果您想确定管道中的 shell 命令 运行 对所有 POSIX-compliant shell 没有副作用,明智的做法是将显式 subshell.

中的整个管道

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

#!/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 更改了行为,例如 while 循环对 index 所做的更改在调用 shell 即使在常见的 shell 上,否则就是这种情况。