here document

备注

在很多shell场合中,我们需要根据模版来替换一些变量。我曾经做过很多次使用 sed 完成变量替换。但是, 私有云部署TLS认证的etcd集群 时,我突然意识到,实际上SHELL实际上早已内置了变量替换功能,只是我一直没有意识到(虽然已经使用过很多次),那就是 here document 。这里我来总结一下 here document 并说明如何使用这个变量替换。

什么是Here Document

Here Document 是Linux Shell 中的一种特殊的重定向方式,它的基本的形式如下:

cmd << delimiter
   Here Document Content
delimiter

它的作用就是将两个 delimiter (分隔符) 之间的内容(Here Document Content 部分) 传递给cmd 作为输入参数。比如在终端中输入 cat << EOF ,系统会提示继续进行输入,输入多行信息再输入EOF,中间输入的信息将会显示在屏幕上。

注意 :

  • EOF 只是一个标识而已,可以替换成任意的合法字符

  • 作为结尾的delimiter一定要顶格写,前面不能有任何字符

  • 作为结尾的delimiter后面也不能有任何的字符(包括空格)

  • 作为起始的delimiter前后的空格会被省略掉

Here Document 不仅可以在终端上使用,在shell 文件中也可以使用,例如下面的 here.sh 文件:

cat << EOF > output.sh
echo "hello"
echo "world"
EOF

使用 sh here.sh 运行这个脚本文件,会得到 output.sh 这个新文件,里面的内容如下:

echo "hello"
echo "world"

通常可以在一个shell脚本中采用上述方法生成新的脚本,这样就可以拆分脚本到多个子脚本进行不同的功能实现

delimiter 与变量

备注

关键点 来了

可以看到上文中我提到了采用 here document 来形成新的脚本,事实上我也经常这样做。但是,既然是脚本就会使用变量,那么我们把上面的那段 here.sh 脚本修改成使用变量会如何呢:

cat << EOF > output.sh
echo "This is output"
ehco $1
EOF

此时执行:

./here.sh HereDocument

则此时可以看到变量 $1 被展开,也就是最后形成的 output.sh 内容如下:

echo "This is output"
echo HereDocument

问题来了,如果我就是想最后生成的脚本 output.sh 是:

echo "This is output"
echo $1

该怎么搞呢?难道我运行 here.sh 脚本不传递参数就可以么?我们来试试 ./here.sh ,再看一下生成的 output.sh 脚本内容:

echo "This is output"
echo

哦,因为没有传递参数 $1 是空的,生成的新脚本 output.sh 展开了变量,只给我留下了一行 echo 。这不符合我的预想

如果不想展开变量 可以在 delimiter 的前后添加 " 来实现,也就是 here.sh 脚本修改成:

cat << "EOF" > output.sh   #注意引号
echo "This is output"
echo $1
EOF

则再次执行 ./here.sh ,就会看到生成的 outpush.sh 脚本内容:

echo "This is output"
echo $1

备注

实际案例请参考 私有云部署TLS认证的etcd集群

参考