`eval` 是否将 shell 应用于以下命令的重定向部分?

`eval` 是否将 shell 应用于以下命令的重定向部分?

当用于eval命令时,是否eval将 shell 两次应用于命令的重定向部分?

假设重定向中的文件名包含空格,如果eval多次对其应用所有解析、shell 扩展和分词等步骤,则在第二轮分词步骤中,文件名将被拆分为两个单词。

以下示例是否意味着eval不会对以下命令的重定向部分应用两次 shell,因此文件名不会拆分为两个单词?

$ filename="my file"
$ eval "cat" < "$filename"
hi

答案1

在您提供的示例中,唯一的事情evalcat,重定向发生在外部,eval并且文件作为命令的标准输入提供eval "cat"

一种变体是使用单引号引用整个命令,包括重定向:

$ eval 'cat < "$filename"'
hi

现在eval正在获取整个字符串,包括重定向和变量名,因此它正在执行变量扩展以及所需的带空格的文件名引用。这仍然有效。

另一种选择是对字符串使用双引号:

$ eval "cat < '$filename'"
hi

现在,该变量由 shell 扩展,但这仍然有效,因为其中的引号将文件名保持在一起。 (请注意,如果文件名包含撇号,这会中断。)

什么“行不通”是这样的:

$ eval "cat" "<" "$filename"

这与您的示例类似,但是使用引号<,外部 shell 不会执行重定向。eval然后将参数放在一起,生成的命令将是:

cat < my file

这不会按预期工作,因为周围的引号my file现在已经消失了......

答案2

其工作方式eval是将参数一起构造为一个 shell 命令来运行。由于你的变量filename 被引用,不会进行分词什么时候命令被构建为运行。

同样的情况可能不适用于文件名带有空格的情况,并且不带引号的扩展将导致错误。例如

filname=my\ file
echo "dude" > my\ file
eval cat < $filename
bash: $filename: ambiguous redirect

请注意此处完成的分词,并cat收到用于输入重定向的不正确文件名,从而导致错误。

另请注意,如果使用时不进行重定向cat,如果直接在文件上使用,在这种情况下eval将打开两个文件,即cat

eval cat $filename

将转化为跑步

cat my file

例如,如果当前目录中有指定的文件,它将显示其内容并显示错误流上file指定的文件不存在。my

filename=my\ file
echo "foo" > file

我们正在使文件my不存在

eval cat $filename 2>&1
cat: my: No such file or directory
foo

相关内容