简介 heredoc-爱代码爱编程
在编写 shell 脚本时,你可能需要将多行文本或代码块传递给交互式命令,例如 tee 、cat 或 sftp.
在 Bash 和其他 shell(如 Zsh)中,Here-document
(Heredoc
) 是一种重定向类型,允许您将多行输入传递给命令。
语法介绍
HereDoc 的语法如下:
[COMMAND] <<[-] 'DELIMITER'
HERE-DOCUMENT
DELIMITER
- 第一行以指定的命令开头,后跟特殊的重定向运算符
<<
和结束符。 - 可以使用任何字符串作为结束符,最常用的是
EOF
和END
- 如果结束符不带引号,则 shell 将替换所有变量、命令和特殊字符,然后再将 here-document 行传递给命令。
- 将减号附加到重定向运算符, 即
<<-
,将导致输出时删除heredoc内行首的所有\t
, 但不会删除空格。 - 最后一行以结束符结尾。结束符前面不允许有空格。
基本示例
Heredoc 经常和 cat 命令一起使用。
示例-1. 引号作用于结束符将不替换
cat << EOF
The current working directory is: $PWD
You are logged in as: $(whoami)
EOF
Output就是:
The current working directory is: /home/abc
You are logged in as: abc
那么如果把结束符用双引号括起来会怎么样呢? 那么,环境变量就不会被替换,而命令也不会被执行。
$ cat << "EOF"
The current working directory is: $PWD
You are logged in as: $(whoami)
EOF
The current working directory is: $PWD
You are logged in as: $(whoami)
示例-2. <<
后加上减号-
则在输出时将Heredoc块内的行首的所有\t
消除
注意,如果以空格开头,则空格不会被消除;只会消除行开头的\t
,哪怕是多个\t
,都会被消除。
cat << EOF
Line without a leading tab.
EOF
Line without a leading tab.
示例-3. 重定向输出到文件
cat << EOF > file.txt
The current working directory is: $PWD
You are logged in as: $(whoami)
EOF
cat file.txt
The current working directory is: /home/abc
You are logged in as: abc
示例-4. 管道输出到sed
下面的例子将单词中的o
替换成a
cat <<'EOF' | sed 's/o/a/g'
Hellooo
Woorld
EOF
Hellaaa
Waarld
也可以先管道给sed
,再输出到文件。
cat <<'EOF' | sed 's/l/e/g' > file.txt
Hello
World
EOF
cat file.txt
Heeeo
Wored
使用Heredoc来操作SSH
要通过ssh在远程系统上执行多个命令,Heredoc是最方便和最简单的方式之一。
示例-5. 使用不带引号的结束符时,请确保转义所有变量、命令和特殊字符,否则它们将在本地插值
ssh -T def@server_side.com << EOF
echo "The current local working directory is: $PWD"
echo "The current remote working directory is: \$PWD"
EOF
Copy
The current local working directory is: /home/abc
The current remote working directory is: /home/def
注意,上面第二个$PWD
前面需要转义,因为此时想取远程机器的PWD变量。
示例-6. 用户输入密码,Heredoc配合expect,在远程机器上执行命令
以下是一个shell脚本的内容。这个脚本能够接收用户的输入作为密码,然后以此访问一个远程机器。
#!/usr/bin/sh
echo -n "Please input password for remote system:"
read -s password
/usr/bin/expect <<- EOF | tee /home/abc/123.txt
spawn ssh abc@some_host ls -l
set timeout 5
expect "abc@some_host's password: "
send -- "$password\r"
expect eof
EOF
(END)