'cat > some_file < EOF some_stuff EOF' 和 'echo "some_stuff" > some_file' 之间有什么区别

'cat > some_file < EOF some_stuff EOF' 和 'echo "some_stuff" > some_file' 之间有什么区别

这是一个知识问题,也是一个研究问题。

我不太清楚为什么我应该使用这个代码:

cat > $FILE << EOF
command1 $var_this_routine
command2 \$var_attached_routine
...
EOF

还有一次是这样的:

echo "command1 $var_this_routine
command2 \$var_attached_routine
...
" > $FILE

嗯,我看到的是类似的报价,但功能和结果相同。对我来说,到目前为止,看起来只是另一个报价。

要附加一些内容,我可以使用“>> $FILE”,其行为方式相同。

但是现在它们之间的技术差异是什么?这些变体有哪些优点或缺点?

答案1

引用、扩展变量等

此处文档 ( <<)允许你传递引号而不进行转义。它还让你决定是否应该进行某些扩展以不干扰您需要传递的报价的方式。


尝试:

var="12  3"
cat <<EOF
'$var"
EOF

输出为

'12  3"

要获得此功能,echo您需要以下之一:

echo "'$var"'"'
echo "'$var\""

或者类似丑陋的东西。通过查看这些命令,很难判断输出应该是什么,而这里的文档却非常清楚。


如果你不想让变量被扩展怎么办?你可以这样做:

cat <<'EOF'
'$var"
EOF

输出实际上是

'$var"

再次强调,此处的文档非常清晰。比较以下命令:

echo "'\$var\""
echo "'"'$var"'

在某些情况下,你仍然需要逃避一些事情。例如

var="12  3"
cat <<EOF
We need '\$var" to be expanded and look like this: '$var"
EOF

要得到

We need '$var" to be expanded and look like this: '12  3"

但即使echo如此更差

echo "We need '\$var\" to be expanded and look like this: '$var\""
echo 'We need '"'"'$var" to be expanded and look like this: '"'$var"'"'

您能轻松预测最后一个的确切输出吗echo?现在想象一下,您需要在文字look和之间添加一个要扩展的变量like。是look like在现有命令中的单引号中还是双引号中?

  • 如果用单引号括起来,那么代码片段应该变成look '"$foo"' like
  • 如果用双引号括起来,那么代码片段应该变成look $foo like

一般来说,引号内可以有引号,并且只有外在的东西才重要,因此要判断使用哪种解决方案,您需要从头(或从尾)解析整个字符串,应用一些启发式方法或只是进行反复试验。

回到此处的文档。由于内容清晰,因此很容易做出正确的更改。echo引用狂热可能会更难维持。


流程

运行脚本的 shell 会处理此处文档。shell 看到

cat >"$file" <<EOF

它知道所有必需的重定向。它可以读取以下几行逐个cat随时将它们传递给。我不是说它总是这样,我是说从技术上来说可能的适用于任意长度的此处文档。

另一方面,在 shell 看到

echo "command1 $var_this_routine

它需要读取整个多行字符串才能发现最后的重定向:

" >"$file"

即使我们一开始

>"$file" echo "command1 $var_this_routine

shell 无法确定是否还有重定向,直到它到达结束位置"。要知道如何处理字符串,shell 必须读取并记住所有的的。

然后它需要将字符串传递给echo(或printf)。在许多 shell 中,echo它是一个内置命令,它可能(也可能不支持)支持非常长的参数。但echo它不一定是 shell 内置命令,它可能只是一个单独的可执行文件。在这种情况下,shell 需要将字符串传递给可执行文件,然后有一些限制

因此,如果任何事情都会失败,那么很可能是echo方法的问题,而不是这里的文档的问题。

答案2

我认为它可以追溯到 Bourne shell 和/或 csh 的旧时代。在 90 年代,多行回显实际上效果不佳,而且您必须小心回显的内容,如果内容包含双引号,它可能会比预期更早地终止字符串。

所以那时我们在 shell 脚本中大量使用“<< EOF”样式。

快进到现在,一些旧的 shell 脚本仍然存在,并且/或者您仍然希望运行它们,即使多行回显更加强大,shell 仍然接受“<< EOF”样式。它还允许您在“<< EOF”部分内添加额外的文本,而无需过多关注语法。

相关内容