如何在Shell脚本中使用Heredoc?
Here文档(Heredoc)是一种输入或文件流文字,被视为特殊的代码块。这个代码块将被传递给命令进行处理。Heredoc起源于UNIX Shell,可以在shell中找到,如sh、tcsh、ksh、bash、zsh、csh。值得注意的是,其他编程语言如Perl、Ruby、PHP也支持heredoc。
一、Heredoc的结构
Heredoc使用两个尖括号(<<
)后跟一个分隔符令牌。相同的分隔符令牌将用于终止代码块。在分隔符内出现的任何内容都被视为代码块。
看下面的示例。我正在将代码块重定向到cat命令。这里,分隔符设置为“BLOCK”,并以相同的“BLOCK”终止。
cat << **BLOCK**
Hello world
Today date is $(date +%F)
My home directory = ${HOME}
**BLOCK**
注意:你应该使用相同的分隔符令牌来开始和终止代码块。
二、创建多行注释
如果你现在在bash中编码,你可能知道bash默认不支持像C或Java那样的多行注释。你可以使用HereDoc来克服这个问题。
这不是bash支持多行注释的内置特性,而只是一种技巧。如果你没有将heredoc重定向到任何命令,解释器将简单地读取代码块,而不会执行任何操作。
<< **COMMENT**
This is comment line 1
This is comment line 2
This is comment line 3
**COMMENT**
三、处理空白符
默认情况下,Heredoc不会抑制任何空白字符(制表符、空格)。我们可以通过在(<<)
后添加dash (-)
,然后是一个分隔符,来覆盖这种行为。这将抑制所有的制表符空格,但不会抑制空格。
cat <<- BLOCK
This line has no whitespace.
This line has 2 white spaces at the beginning.
This line has a single tab.
This line has 2 tabs.
This line has 3 tabs.
BLOCK
四、变量和命令替换
Heredoc接受变量替换。变量可以是用户定义的变量或环境变量。
TODAY=$(date +%F)
cat << BLOCK1
# User defined variables
Today date is = ${TODAY}
#Environ Variables
I am running as = ${USER}
My home dir is = ${HOME}
I am using ${SHELL} as my shell
BLOCK1
类似地,你可以在Heredoc代码块内运行任何命令。
cat << BLOCK2
$(uname -a)
BLOCK2
五、转义特殊字符
有几种方法可以转义特殊字符。你可以在字符级别或文档级别进行转义。
要转义单个特殊字符,请使用反斜杠 (\)。
cat << BLOCK4
$(uname -a)
BLOCK4
cat << BLOCK5
Today date is = ${TODAY}
BLOCK5
要转义代码块内的所有特殊字符,请用单引号、双引号包围分隔符,或在分隔符前加反斜杠。
cat << 'BLOCK1'
I am running as = ${USER}
BLOCK1
cat << "BLOCK2"
I am running as = ${USER}
BLOCK2
cat << \BLOCK3
I am running as = ${USER}
BLOCK3
六、SSH批量命令
现在已经了解了Heredoc的结构和工作原理,最常用的场景是在通过SSH运行命令块和通过Heredoc传递SQL查询。
在下面的示例中,将一个select语句传递给psql,以连接到数据库并运行查询。这是在bash脚本中运行psql查询的一种替代方法,而不是使用-f
标志来运行.sql文件。
#!/usr/bin/env bash
UNAME=postgres
DBNAME=testing
psql --username=${UNAME} --password --dbname=${DBNAME} << BLOCK
SELECT * FROM COUNTRIES
WHERE region_id = 4;
BLOCK
Heredoc除了可以适用上面SSH的批量命令的场景,还可以适用更多的场景如多行字符串处理,发布等等场景。