如何 cat <<EOF >> 包含代码的文件?

Posted

技术标签:

【中文标题】如何 cat <<EOF >> 包含代码的文件?【英文标题】:How to cat <<EOF >> a file containing code? 【发布时间】:2014-05-07 00:30:17 【问题描述】:

我想使用cat &lt;&lt;EOF &gt;&gt;将代码打印到文件中:

cat <<EOF >> brightup.sh
!/bin/bash
curr=`cat /sys/class/backlight/intel_backlight/actual_brightness`
if [ $curr -lt 4477 ]; then
   curr=$((curr+406));
   echo $curr  > /sys/class/backlight/intel_backlight/brightness;
fi
EOF

但是当我检查文件输出时,我得到了这个:

!/bin/bash
curr=1634
if [  -lt 4477 ]; then
   curr=406;
   echo   > /sys/class/backlight/intel_backlight/brightness;
fi

我尝试使用单引号,但输出也带有单引号。我怎样才能避免这个问题?

【问题讨论】:

你也应该修复shebang。第一行必须是字面上的#!/bin/bash,没有别的——#! 是使它成为有效的 shebang 行的原因,之后是解释器的路径。 顺便说一句,进程替换的现代语法是$(command),而不是`command`。为了获取文件的内容,Bash 有$(&lt;file) 【参考方案1】:

您只需要很小的改动;在&lt;&lt; 之后单引号引用此处的文档分隔符。

cat <<'EOF' >> brightup.sh

或等效的反斜杠转义它:

cat <<\EOF >>brightup.sh

如果没有引用,这里的文档将像您发现的那样进行变量替换,反引号将被评估等等。

如果您需要扩展一些(但不是全部)值,则需要单独转义要阻止的值。

cat <<EOF >>brightup.sh
#!/bin/sh
# Created on $(date # : <<-- this will be evaluated before cat;)
echo "\$HOME will not be evaluated because it is backslash-escaped"
EOF

会产生

#!/bin/sh
# Created on Fri Feb 16 11:00:18 UTC 2018
echo "$HOME will not be evaluated because it is backslash-escaped"

根据@fedorqui 的建议,这里是来自man bash 的相关部分:

这里的文档

这种类型的重定向指示 shell 从 当前源,直到仅包含分隔符的行(没有 尾随空白)可见。到目前为止读取的所有行都是 然后用作命令的标准输入。

here-documents的格式为:

      <<[-]word
              here-document
      delimiter

没有参数扩展,命令替换,算术扩展, 或对 word 执行路径名扩展。如果单词中有任何字符 被引用,分隔符是单词上引号删除的结果,并且 here-document 中的行没有展开。 如果单词是 未引用,此处文档的所有行都受参数 扩展、命令替换和算术扩展。在里面 后一种情况,字符序列\&lt;newline&gt; 被忽略,\ 必须用于引用字符\$`

【讨论】:

我看到您将 How to avoid heredoc expanding variables? 标记为此邮件的副本。没有异议,只是我会包括 Bash 文档参考,就像我在我的一样(只有 13k 次访问得到了近 100 个代表,所以它似乎很有帮助)。 @fedorqui 也许您实际上想移植您对这个问题的答案?或者我们可以将重复标记切换为相反的方式;我只看题目分数,没看答案分数。 嗯,merging 他们呢,把这个作为目标问题?重复的问题有一个很好的标题,只是它太长了。然而,不知何故,它最近引起了很多关注(我收到了some upvotes per month)。 @fedorqui 我喜欢合并的概念,但我从未见过它在实践中发生;如果我正确理解了情况,模组根本无法处理非平凡的合并,因为麻烦和复杂性远远超过了好处。我所做的一两次是删除一个有用且被赞成的答案,然后在另一个问题下重新发布,尽管我几乎不推荐这种解决方法。 很难说什么时候值得去做。我已经在一个我修改过的网站上完成了它,当时发布了一个好问题,却没有注意到之前还有另一个好问题,两者都有很好的答案。删除我 90 分以上的答案似乎不是一个好计划,因为它会使该问题成为孤儿。【参考方案2】:

或者,使用您的 EOF 标记,您需要引用初始标记,因此不会进行扩展:

#-----v---v------
cat <<'EOF' >> brightup.sh
#!/bin/bash
curr=`cat /sys/class/backlight/intel_backlight/actual_brightness`
if [ $curr -lt 4477 ]; then
   curr=$((curr+406));
   echo $curr  > /sys/class/backlight/intel_backlight/brightness;
fi
EOF

IHTH

【讨论】:

我会编辑您的帖子,但为了安全起见,不应该是 #!/bin/bash 而不是 !/bin/bash? @MatthewHoggan:是的,你说得对!谢谢你抓住那个。我现在正在修复它。【参考方案3】:

这应该可以工作,我刚刚对其进行了测试,它按预期工作:没有发生扩展、替换或你有什么。

cat <<< '
#!/bin/bash
curr=`cat /sys/class/backlight/intel_backlight/actual_brightness`
if [ $curr -lt 4477 ]; then
  curr=$((curr+406));
  echo $curr  > /sys/class/backlight/intel_backlight/brightness;
fi' > file # use overwrite mode so that you don't keep on appending the same script to that file over and over again, unless that's what you want. 

使用以下方法也可以。

cat <<< ' > file
 ... code ...'

另外,值得注意的是,在使用heredocs时,例如&lt;&lt; EOF,会发生替换和变量扩展等。所以做这样的事情:

cat << EOF > file
cd "$HOME"
echo "$PWD" # echo the current path
EOF

将始终导致变量$HOME$PWD 的扩展。所以如果你的主目录是/home/foobar,当前路径是/home/foobar/binfile 将如下所示:

cd "/home/foobar"
echo "/home/foobar/bin"

而不是预期的:

cd "$HOME"
echo "$PWD"

【讨论】:

单引号中的here字符串显然不能包含任何单引号,这可能是一个令人望而却步的问题。如果您的脚本需要同时包含单引号和双引号,那么这里的文档是唯一合理的解决方法,尽管 OP 的简单示例当然不是这种情况。此外,切向地,这里的字符串 &lt;&lt;&lt; 仅从 Bash 3 开始可用,并且不能移植到其他 shell。 &lt;&lt;&lt; 也可以在 Zsh 中使用 今天我了解到,您可以在打开 heredoc 之后立即使用文件名。谢谢@AlexejMagura!【参考方案4】:

我知道这是一个两年前的问题,但对于那些寻找“如何做”的人来说,这是一个快速的答案。

如果您不想在任何内容周围加上引号,您只需将一段文本写入文件,然后转义要导出为文本的变量(例如用于脚本中)而不转义一个您想导出为变量的值。

#!/bin/bash

FILE_NAME="test.txt"
VAR_EXAMPLE="\"string\""

cat > $FILE_NAME << EOF
\$VAR_EXAMPLE=$VAR_EXAMPLE in $FILE_NAME  
EOF

将 "$VAR_EXAMPLE="string" in test.txt" 写入 test.txt

这也可以用于通过省略文件名以相同的规则将文本块输出到控制台

#!/bin/bash

VAR_EXAMPLE="\"string\""

cat << EOF
\$VAR_EXAMPLE=$VAR_EXAMPLE to console 
EOF

将“$VAR_EXAMPLE="string" to console”输出到控制台

【讨论】:

【参考方案5】:

带有&lt;&lt;EOF&gt;&gt; 的cat 将创建内容或将内容附加到现有文件,不会覆盖。而 &lt;&lt;EOF&gt; 的 cat 将创建或覆盖内容。

cat test.txt 
hello

cat <<EOF>> test.txt
> hi
> EOF

cat test.txt 
hello
hi

cat <<EOF> test.txt
> haiiiii
> EOF

cat test.txt
haiiiii

【讨论】:

不回答问题

以上是关于如何 cat <<EOF >> 包含代码的文件?的主要内容,如果未能解决你的问题,请参考以下文章

“cat > filename << EOF”和“cat << EOF > filename”是不是等效? [复制]

mail mysqldd

“cat << EOF”如何在 bash 中工作?

cat <<EOF

Linux CAT与ECHO命令详解 <<EOF EOF

shell用法 (cat << EOF)