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

Ube*_*ate 79 unix linux heredoc sh

我想使用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
Run Code Online (Sandbox Code Playgroud)

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

!/bin/bash
curr=1634
if [  -lt 4477 ]; then
   curr=406;
   echo   > /sys/class/backlight/intel_backlight/brightness;
fi
Run Code Online (Sandbox Code Playgroud)

我尝试使用单引号,但输出也带有单引号.我该如何避免这个问题?

tri*_*eee 127

你只需要一个微小的变化; 单引号后的here-document分隔符<<.

cat <<'EOF' >> brightup.sh
Run Code Online (Sandbox Code Playgroud)

或等效反斜杠 - 逃避它:

cat <<\EOF >>brightup.sh
Run Code Online (Sandbox Code Playgroud)

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

如果需要扩展某些值,而不是所有值,则需要单独转义要防止的值.

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
Run Code Online (Sandbox Code Playgroud)

会产生

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

正如@fedorqui所建议的,以下是相关章节man bash:

这里的文件

这种类型的重定向指示shell从当前源读取输入,直到看到仅包含分隔符(没有尾随空白)的行.然后,读取到该点的所有行都将用作命令的标准输入.

here-documents的格式是:

      <<[-]word
              here-document
      delimiter
Run Code Online (Sandbox Code Playgroud)

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


she*_*ter 19

或者,使用您的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
Run Code Online (Sandbox Code Playgroud)

IHTH


Ale*_*ura 9

这应该有用,我只是测试了它并且它按预期工作:没有扩展,替换,或者你发生了什么.

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. 
Run Code Online (Sandbox Code Playgroud)

使用以下也有效.

cat <<< ' > file
 ... code ...'
Run Code Online (Sandbox Code Playgroud)

此外,值得注意的是,当使用heredoc时,例如<< EOF,替换和可变扩展等发生.所以做这样的事情:

cat << EOF > file
cd "$HOME"
echo "$PWD" # echo the current path
EOF
Run Code Online (Sandbox Code Playgroud)

总是会导致变量$HOME和扩展$PWD.因此,如果您的主目录是/home/foobar当前路径/home/foobar/bin,file则如下所示:

cd "/home/foobar"
echo "/home/foobar/bin"
Run Code Online (Sandbox Code Playgroud)

而不是预期的:

cd "$HOME"
echo "$PWD"
Run Code Online (Sandbox Code Playgroud)

  • 今天我了解到你可以在heredoc的开头跟随文件名.谢谢@AlexejMagura! (3认同)
  • 单引号中的here字符串显然不能包含任何单引号,这可能是一个禁止的问题。如果您的脚本需要同时包含单引号和双引号,则这里的文档是唯一可行的解​​决方法,尽管对于OP的简单示例而言并非如此。同样,从切线开始,这里字符串`&lt;&lt;&lt;`仅从Bash 3开始可用,不可移植到其他shell。 (2认同)

GCU*_*rea 7

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

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

#!/bin/bash

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

cat > ${FILE_NAME} << EOF
\${VAR_EXAMPLE}=${VAR_EXAMPLE} in ${FILE_NAME}  
EOF
Run Code Online (Sandbox Code Playgroud)

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

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

#!/bin/bash

VAR_EXAMPLE="\"string\""

cat << EOF
\${VAR_EXAMPLE}=${VAR_EXAMPLE} to console 
EOF
Run Code Online (Sandbox Code Playgroud)

将输出 '"${VAR_EXAMPLE}="string" 到控制台'