意外标记“(”附近的语法错误

Nec*_*cco 15 shell

当我在 CentOS 的 SSH 终端中使用以下代码时,它工作正常:

paste <(printf "%s\n" "TOP")
Run Code Online (Sandbox Code Playgroud)

但是,如果我将相同的行代码放在 shell 脚本(test.sh)中并从终端运行 shell 脚本,它会抛出错误,如下所示

./test.sh: line 30: syntax error near unexpected token ('   
./test.sh: line 30:     paste <(printf "%s\n" "TOP")
Run Code Online (Sandbox Code Playgroud)

我该如何解决这个问题?

cuo*_*glm 28

POSIX 未指定进程替换,因此并非所有 POSIX shell 都支持它,只有一些 shell,如bash, zsh, ksh88, ksh93

在 CentOS 系统中,/bin/sh是指向/bin/bash. 当bash使用 name 调用时shbash进入 posix 模式(Bash 启动文件 - 使用名称 sh 调用)。在 5.1 之前的 bash 版本中,在 posix 模式下调用时禁用进程替换支持,从而导致语法错误。

如果您bash直接调用,该脚本应该可以工作:bash test.sh。如果没有,可能bash已经进入posix模式。如果你一开始可能发生这种情况bash--posix参数或者变量POSIXLY_CORRECT被设置时bash开始:

$ bash --posix test.sh 
test.sh: line 54: syntax error near unexpected token `('
test.sh: line 54: `paste <(printf "%s\n" "TOP")'

$ POSIXLY_CORRECT=1 bash test.sh 
test.sh: line 54: syntax error near unexpected token `('
test.sh: line 54: `paste <(printf "%s\n" "TOP")
Run Code Online (Sandbox Code Playgroud)

或者bash是用--enable-strict-posix-default选项构建的。

在这里,您不需要进程替换,您可以使用标准的 shell 管道:

printf "%s\n" "TOP" | paste -
Run Code Online (Sandbox Code Playgroud)

-是告诉paste从 stdin 读取数据的标准方法。对于某些paste实现,您可以省略它,尽管这不是标准的。

在粘贴多个命令的输出时会有用,例如:

paste <(cmd1) <(cmd2)
Run Code Online (Sandbox Code Playgroud)

在支持 的系统上/dev/fd/n,可以通过以下方式完成sh

{ cmd1 4<&- | { cmd2 3<&- | paste /dev/fd/3 -; } 3<&0 <&4 4<&-; } 4<&0
Run Code Online (Sandbox Code Playgroud)

(这是<(...)内部所做的)。