标准sed不能调用shell(GNU sed具有扩展名可以执行此操作)如果您只关心非嵌入式Linux,则),因此您必须在sed之外进行一些处理。有几种解决方案。所有这些都需要仔细报价。
尚不清楚您希望如何扩展值。例如,如果一行是
foo hello; echo $(true) 3
输出应为以下哪个?
k=<foo> value=<hello; echo 3>
k=<foo> value=<hello; echo 3>
k=<foo> value=<hello; echo 3>
k=<foo> value=<foo hello
3>
我将在下面讨论几种可能性。
纯壳
您可以使外壳逐行读取输入并进行处理。这是最简单的解决方案,对于短文件也是最快的解决方案。这是最符合您要求的“ echo \2
”:
while read -r keyword value; do
echo "k=<$keyword> v=<$(eval echo "$value")>"
done
read -r keyword value
设置$keyword
为该行的第一个空格分隔的单词,并且$value
设置为该行的其余部分减去尾随空格。
如果你想扩展变量引用,但不执行命令以外的命令替换,把$value
一个内这里的文档。我怀疑这就是您真正想要的。
while read -r keyword value; do
echo "k=<$keyword> v=<$(cat <<EOF
$value
EOF
)>"
done
sed用管道输送到外壳中
您可以将输入转换为Shell脚本并进行评估。Sed可以完成任务,尽管并非易事。符合您的“ echo \2
”要求(请注意,我们需要对关键字中的单引号进行转义):
sed -e 's/^ *//' -e 'h' \
-e 's/[^ ]* *//' -e 'x' \
-e 's/ .*//' -e "s/'/'\\\\''/g" -e "s/^/echo 'k=</" \
-e 'G' -e "s/\n/>' v=\\</" -e 's/$/\\>/' | sh
在here文档中,我们仍然需要对关键字进行转义(但要有所不同)。
{
echo 'cat <<EOF'
sed -e 's/^ */k=</' -e 'h' \
-e 's/[^ ]* *//' -e 'x' -e 's/ .*//' -e 's/[\$`]/\\&/g' \
-e 'G' -e "s/\n/> v=</" -e 's/$/>/'
echo 'EOF'
} | sh
如果您有很多数据,这是最快的方法:它不会为每一行启动一个单独的过程。
awk
我们在awk的sed中使用的相同技术。生成的程序更具可读性。与“ echo \2
”一起使用:
awk '
1 {
kw = $1;
sub(/^ *[^ ]+ +/, "");
gsub(/\047/, "\047\\\047\047", $1);
print "echo \047k=<" kw ">\047 v=\\<" $0 "\\>";
}' | sh
使用此处文档:
awk '
NR==1 { print "cat <<EOF" }
1 {
kw = $1;
sub(/^ *[^ ]+ +/, "");
gsub(/\\\$`/, "\\&", $1);
print "k=<" kw "> v=<" $0 ">";
}
END { print "EOF" }
' | sh