子shell和进程替换

子shell和进程替换

如果这是一个基本问题,我深表歉意 - 我一直在尝试解决一个更大的问题,这取决于如何调用 shell 脚本 - 直接 ( shellScript.sh) 或使用sh shellScript.sh.

这是该问题的模型:

当我在 bash 上执行时:

cat <(echo 'Hello')

我看到输出

Hello

但是当我使用时:

sh -c "cat <(echo 'Hello')"

我看到错误:

sh: -c: line 0: syntax error near unexpected token `('
sh: -c: line 0: `cat <(echo 'Hello')'

我尝试过以各种组合转义<,(),但我在任何地方都看不到输出。我在这里缺少什么?

我的实际问题是,我将 a<()作为输入参数传递给 shell 脚本中的 python 脚本,虽然当我仅使用名称调用 shell 脚本时它工作正常,但如果我用来sh调用它,我会收到类似的错误到我上面所展示的。

谢谢你!

答案1

进程替换是一项起源于 80 年代 Korn shell 的功能(首次记录在 ksh86 中)。当时,它仅适用于支持/dev/fd/<n>文件的系统。

后来,该功能又被添加到zsh(从1990年开始)和bash(从1993年开始)。zsh正在使用临时命名管道来实现它,而bash正在使用/dev/fd/<n>可用的地方和其他命名管道。1996 年zsh改用/dev/fd/<n>可用的地方。2.6-beta17

2012年/dev/fd才添加了对通过命名管道在系统上进行进程替换的支持。的公共域克隆不支持它。kshksh93u+ksh

据我所知,没有其他类似 Bourne 的 shell 支持它(rcesfish、非类似 Bourne 的 shell 支持它,但语法不同)。yash有一个<(...)构造,但那是为了进程重定向

虽然非常有用,但该功能从未被 POSIX 标准化。因此,人们不能期望在 中找到它sh,因此不应在sh脚本中使用它。

尽管 POSIX 中未指定 的行为<(...)(因此保留它不会有什么坏处),但在其环境中bash调用 assh或 with 时会禁用该功能。POSIXLY_CORRECT=1

因此,如果您有一个使用 的脚本<(...),则应该使用支持该功能的 shell 来解释它,例如zshbash或 AT&T ksh(当然,您需要确保脚本的其余语法也与该 shell 兼容)。

任何状况之下:

cat <(cmd)

可以写成:

cmd | cat

要不就

cmd

cat对于除(需要通过作为参数给出的文件传递数据)之外的命令,在具有 的系统上/dev/fd/x,您始终可以执行以下操作:

something | that-cmd /dev/stdin

或者,如果您需要that-cmd保留 的 stdin:

{ something 3<&- | that-cmd /dev/fd/4 4<&0 <&3 3<&-; } 3<&0 

相关内容