为什么进程替换在脚本中不起作用?

Why process substitution doesn’t work in a script?

一条简单的线

$ read a b < <(sed -nr '$ s/.*(123).*(456).*/ /p' <<<"fds 123 fdsf 456 f")
$ echo $a - $b
123 - 456

在终端中工作,但被放入脚本中

$ echo -e '#!/bin/bash\nread a b < <(sed -nr '$ s/.*(123).*(456).*/ /p' <<<"fds 123 fdsf 456 f")\necho $a - $b' >/tmp/t
$ chmod +x /tmp/t
$ /tmp/t

报错

/tmp/t: command substitution: line 3: syntax error near unexpected token `('
/tmp/t: command substitution: line 3: `sed -nr $ s/.*(123).*(456).*/1 2/p <<<"fds 123 fdsf 456 f")'

我怀疑它与 read 由于某种原因无法访问的脚本的标准输入有某种关系,但我无法弄清楚它到底需要什么。


我在写文件的例子中犯了一个错误,但它与问题无关。假设带有 read 的行在终端和脚本版本中看起来完全一样。问题是为什么它不能放在文件中。

您没有正确编写脚本。执行此类操作的最简单方法是使用 heredoc:

cat > /tmp/t << \EOF
#!/bin/bash
read a b < <(sed -nr '$ s/.*(123).*(456).*/ /p' <<<"fds 123 fdsf 456 f")
echo $a - $b
EOF
chmod +x /tmp/t
/tmp/t

您在两个完全不同的引用场景中使用流程替换。第一:

read a b < <(sed -nr '$ s/.*(123).*(456).*/ /p' <<<"fds 123 fdsf 456 f")

此处您正在使用 进程替换 将结果提供给 read:

sed -nr '$ s/.*(123).*(456).*/ /p' <<<"fds 123 fdsf 456 f"

到您阅读的声明 -- 很好。不存在报价问题。 (但是,当简单重定向应该执行时,您使用 herestring 是值得怀疑的)。

在您的第二个命令中 line/script 尝试:

$ echo -e '#!/bin/bash\nread a b < <(sed -nr '$ s/.*(123).*(456).*/ /p' <<<"fds 123 fdsf 456 f")\necho 

您未正确使用 单引号 ,这会提前终止您的命令,使其不完整。用 双引号 替换第二组单引号(反之亦然):

echo -e '#!/bin/bash\nread a b < <(sed -nr "$ s/.*(123).*(456).*/ /p" <<<"fds 123 fdsf 456 f")\necho'

echo对进程替换一无所知,它只知道什么时候有一个左单引号',然后下一个应该是一个右单引号...

问题出在引用上,用这个来写脚本:

cat <<'EOF' >script
#!/bin/bash
read a b < <(sed -nr '$ s/.*(123).*(456).*/ /p' <<<"fds 123 fdsf 456 f")
echo $a $b
EOF

此处文档中的引用 <<'EOF' 禁用脚本中的参数扩展。

虽然我仍然不明白为什么进程替换不起作用,但这个解决方法帮助了我

read a b <<EOF
$(sed -nr '$ s/.*(123).*(456).*/ /p' <<<"fds 123 fdsf 456 f")
EOF

您可能需要在 sed 之前指定 IFS,例如

$(IFS=' '; sed -nr '$ s/.*(123).*(456).*/ /p' <<<"fds 123 fdsf 456 f")

对于这个例子。