如何对<< EOF >>包含代码的文件进行分类?


101

我想使用cat <<EOF >>以下代码将代码打印到文件中:

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

我试过用单引号引起来,但输出中也带有单引号。如何避免这个问题?


2
您还应该修复shebang。第一行必须是字面上的内容,#!/bin/bash而不是其他任何内容- #!是什么使它成为有效的shebang行,其后才是到达解释器的路径。
2015年

1
看到man bash并搜索Here Documents。那里的所有细节。

1
作为一个后起之余,工艺替代现代语法$(command)代替`command`。为了获取文件的内容,Bash具有$(<file)
三位一体的用户

Answers:


159

您只需要进行最小的更改;在此处单引号此处文档分隔符<<

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以下内容的相关部分:

这里文件

这种重定向指示外壳程序从当前源读取输入,直到看到仅包含定界符(无尾随空格)的行。直到该点为止读取的所有行都将用作命令的标准输入。

此处文档的格式为:

      <<[-]word
              here-document
      delimiter

对单词不执行参数扩展,命令替换,算术扩展或路径名扩展。如果单词中的任何字符被加引号,则分隔符是单词上的引号删除的结果,并且本文档中的行不会扩展。 如果未引用word,则对本文的所有行进行参数扩展,命令替换和算术扩展。在后一种情况下,字符序列\将被忽略,并且\必须用于引用字符\,$和`。


1
我看到您标记了如何避免heredoc扩展变量?作为此副本的副本。没有异议,只是我将包括Bash文档参考,就像我在我的工作中所做的一样(只有1万3千次访问获得了近100次代表,因此似乎很有帮助)。
fedorqui'SO停止伤害'18

@fedorqui也许您实际上想移植对这个问题的答案?或者我们可以将重复标记改为相反的方式;我只是看着问题分数,而不是答案分数。
Tripleee

嗯,它们合并为目标问题,合并它们呢?重复的问题有一个很好的标题,只是太长了。但是,它最近以某种方式引起了很多关注(我每个月都会得到一些支持)。
fedorqui'SO停止伤害'18

@fedorqui我喜欢合并的概念,但我从未见过在实践中发生;如果我正确地理解了情况,那么mod根本无法处理非平凡的合并,因为麻烦和复杂性远远超过了好处。我曾经做过一两次的工作是删除一个有用的,被推崇的答案,然后将其重新发布到另一个问题下,尽管我很难推荐这种解决方法。
Tripleee

很难说出什么时候值得做。我在我修改的网站上完成了该工作,当时发布了一个好问题,却没有注意到之前有另一个好问题,两个问题都有很好的答案。删除我的90分以上的答案似乎不是一个好计划,因为这会使该问题变成孤儿。
fedorqui'SO停止伤害'18

20

或者,使用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

高温超导


1
我会编辑您的帖子,但是为了安全起见,它应该不是#!/ bin / bash而不是!/ bin / bash吗?
马修·霍根

@MatthewHoggan:是的,你是对的!感谢您抓住这一点。我正在修复它。
Shellter

16

这应该行得通,我刚刚对其进行了测试,并按预期工作了:没有进行任何扩展,替换或任何操作。

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时,<< 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"

2
单引号中的here字符串显然不能包含任何单引号,这可能是一个禁止的问题。如果您的脚本需要同时包含单引号和双引号,那么这里的文档是唯一可行的解​​决方法,尽管对于OP的简单示例而言并非如此。同样,从切线开始,这里字符串<<<仅从Bash 3开始可用,不能移植到其他shell。
2015年

<<<在Zsh中也可用
Alexej Magura

3
今天,我了解到您可以立即在heredoc的开头跟随文件名。谢谢@AlexejMagura!
chaseadamsio
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.