bash 变量输入时通讯失败

bash 变量输入时通讯失败

我有一个脚本应该获取两个目录的文件列表,获取差异并为某些文件执行一些代码。

这些是获取文件列表的命令:

list_in=$(find input/ -maxdepth 1 - type f | sed 's/input\///' | sort -u);
list_out=$(find output/ -maxdepth 1 - type f | sed 's/output\///' | sort -u);

我在正确的目录中执行脚本,所以这应该不会失败。未处理的文件由下式确定

list_todo=$(comm -23 <(echo "$list_in") <(echo "$list_out"));

由于选项-23forcomm仅打印第一个参数的行,该行不会出现在两个参数中,并且不会打印唯一出现在第二个参数中的行。

但是,偶尔我会收到错误消息

command substitution: line 3: syntax error near unexpected token `('
command substitution: line 3: `comm -23 <(echo "$list_in") <(echo "$list_out")'

这真的让我很困惑,因为完全相同的脚本在过去三周内运行良好。我在集群上使用它,因此多个进程可能会同时执行该脚本。错误可能是由这个引起的吗?

更新。该脚本是通过调用的./script,并且我之前显然已设置过chmod +x script

(免责声明:即使我正在集群上工作,并且我的脚本的前三行不包含任何锁定机制:当然,没有文件会被处理两次)

答案1

内核识别可以本机执行的某些文件格式。这包括至少一种二进制格式。此外,以#!(舍邦) 被视为脚本;例如,如果文件位于/path/to/script并以 开头,那么当您调用 时,#!/bin/bash内核就会执行。/bin/bash /path/to/script arg1 arg2/path/to/script arg1 arg2

如果内核无法识别该文件格式,则会从该文件返回 ENOEXEC(执行格式错误)execve系统调用。遵循古代 Unix 内核没有 shebang 功能的传统,大多数程序在第一次尝试失败并出现错误 ENOEXEC 时会再次尝试执行程序:它们尝试/bin/sh作为脚本解释器执行。

Bash 是一个值得注意的例外:它在自身中运行脚本,而不是在/bin/sh.因此,当您从 bash 调用脚本时,您的脚本意外地工作了。

如果您省略 shebang 行,您的脚本可能会在/bin/bash或 下执行/bin/sh,具体取决于执行它的程序。并且/bin/sh显然不支持您的系统上的进程替换。它可能仍然是 bash (错误消息看起来像来自 bash 的错误消息),但是当在名称下调用 bash 时sh,它会进入不支持进程替换的 POSIX 兼容模式。

这个故事的寓意是:如果你写一个 bash 脚本,你必须把它放在#!/bin/bash第一行。

答案2

$() 和 <() 构造仅适用于 bash。这意味着您需要将 shebang 行设置为:

#!/bin/bash

特别是这将不是工作:

#!/bin/sh

如果你需要它来工作,sh那么你可以使用 ` 而不是 $():

list_in=`find input/ -maxdepth 1 - type f | sed 's/input\///' | sort -u`

您可以使用 mkfifo 代替 <()。

相关内容