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

问题描述 投票:0回答:6

我想使用

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

我尝试添加单引号,但输出也带有单引号。如何避免这个问题?

linux unix sh heredoc
6个回答
300
投票

您只需要一点点改变;在

<<
之后用单引号引用此处文档分隔符。

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 从 当前源直到仅包含定界符的行(没有 看到尾随空白)。到该点为止读取的所有行都是 然后用作命令的标准输入。

此处文档的格式为:

      <<[-]word
              here-document
      delimiter

无参数扩展、命令替换、算术扩展、 或对 word 执行路径名扩展。如果word中有任何字符 被引用,分隔符是对单词去除引号的结果,并且 此处文档中的行未展开。 如果单词是 不加引号,此处文档的所有行均受参数影响 扩展、命令替换和算术扩展。在里面 后一种情况,字符序列

\<newline>
被忽略,并且
\
必须用于引用字符
\
$
`

有关相关问题,另请参阅 https://stackoverflow.com/a/54434993


36
投票

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

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/bin
,则
file
将如下所示:

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

而不是预期的:

cd "$HOME"
echo "$PWD"

32
投票

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


7
投票

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

如果您不想在任何内容周围加上引号,您可以简单地将一段文本写入文件,并转义您想要导出为文本的变量(例如在脚本中使用),而不是转义您想要的变量导出为变量的值。

#!/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" 到控制台'


1
投票

cat 与

<<EOF>>
将创建或追加内容到现有文件,不会覆盖。而带有
<<EOF>
的 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

0
投票

不确定不使用 bash 是否可以算作答案。

python -c 'with open("brightup.sh", "w") as fp: fp.write("""
!/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""")'

或将脚本粘贴到控制台(最后按 Ctrl+d):

python -c 'import sys; fp= open("brightup.sh", "w"); print("paste script:"); fp.write("".join(sys.stdin.readlines())); fp.close()'
© www.soinside.com 2019 - 2024. All rights reserved.