shell heredoc 微妙之处

here doc 的一般用法:

[cmd] <<word
   here-document
delimiter

 

可以把 heredoc 的内容放进文件,也可以放进 shell 变量,参见以下代码:

#!/bin/sh

# write heredoc text to file
cat > file <<EOF
some text write to file
EOF

# show file
cat file

# save heredoc text to var
var=`cat << EOF
some text save to var
EOF
`
# show var
echo $var


 

使用`` 捕获 heredoc 内容比较丑陋,但这是我目前能找到的不需要中间文件就可以将heredoc内容存到变量中的唯一方式($(..)也可以,但似乎更丑陋,并且移植性更差)。我觉得比较好的捕获heredoc内容的方式应该象这样,不需要在delimiter 之后再放一个标记:

capture var <<"EOF"
 some text 
EOF

 

然而有两点需要注意:

当word中含有双引号(" )时,heredoc结束标记(delimiter )需要写成 按shell 移除引号的规则 移除引号之后 的形式。比如:

word="EOF"

delimiter=EOF

word= "EOF"here"doc1"

delimiter=EOFheredoc1

在这种情况下(word中包含引号),heredoc的文本内容会原原本本地输出,而不会被shell扩展。 反之 (word中无引号) heredoc的内容会按shell扩展规则被扩展,例如将$1扩展成参数等等,并且 \newline 会被删除。

 

还有一种情况,就是重定向 符号 << 可以使用 <<- ,在这种情况下,heredoc 文本中的前导 tab 字符会被删除,还有一点我没太看明白,也没试验出来( all leading tab characters will be stripped from input lines and the line containing the trailing delimiter )。

 

可以使用 heredoc 直接在 shell 中写比较复杂的 awk 程序,比直接在在引号中写要可读、易懂得多:

#!/bin/sh

if [ $# -lt 1 ]
then
        echo usage: $0 files
        exit 1
fi

prog=`cat <<"EOF"
{ count[$1] += $2; } 
END{
   for (k in count) {
        printf "%s\t%d\n", k, count[k];
   }
}
EOF
`
awk "$prog" "$@"

 

 

@see opengroup 上的文档

你可能感兴趣的:(shell)