標準のsedはシェルを呼び出すことができません(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>
以下にいくつかの可能性について説明します。
純粋な殻
シェルに入力を1行ずつ読み取らせて処理させることができます。これは最も単純なソリューションであり、短いファイルでも最速です。これは、要件「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
入力をシェルスクリプトに変換して評価できます。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
ヒアドキュメントを使用して、キーワードをエスケープする必要があります(ただし、異なります)。
{
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