次のような文字列が与えられた場合、 sed のみを使用して短い月の文字列 ("Oct" など) を対応する数値 ("10" など) に置き換えるという興味深い問題が発生しています。
Oct 14 09:23:35 some other input
次のように直接置き換えますsed
。
14-10-2013 09:23:25 some other input
次のどれも実際には、月の文字列から数値への変換という些細な問題の解決には関係ありません。この問題を完全に sed で解決しようとしているときに遭遇した奇妙な動作を理解することにもっと興味があります。
この文字列置換を試みなければ (echo
ステートメントは、スクリプトの実際の入力の代わりになります):
...
MMM_DD_HH_mm_SS="([A-Za-z]{3}) ([0-9]{2}) (.+:[0-9]{2})"
echo "Oct 14 09:23:35 some other input" | sed -r "s/$MMM_DD_HH_mm_ss (.+)/\2-\1-\3 \4/"
次に、後方参照を数値に変換する方法\1
。もちろん、後方参照を引数としてコマンド補間を使用することを考えてみてください。
...
TestFunc()
{
echo "received input $1$1"
}
...
echo "Oct 14 09:23:35 some other input" | sed -r "s/$MMM_DD_HH_mm_ss (.+)/\2-$(TestFunc \\1)-\3 \4/"
入力として 'd 日時グループを使用しTestFunc
たコマンドのバリエーションdate
(以下の Jotne によって提案されている) はどこにありますか。echo
ここで TestFunc はecho
、関数が の値であると信じているものの動作にもっと興味があるためです$1
。
この場合、sed
withTestFunc
は次の出力を生成します。
14-received input OctOct-09:23:35 some other input
これは、sedが実際に(ローカル変数として受け取るように見える)による処理のためにコマンド置換に後方参照を挿入していることを示唆しています。 \1
$(...)
TestFunc
\1
$1
ただし、ローカルでそれ以上のことをしようとすると、すべて$1
失敗します。例えば:
TestFunc()
{
echo "processed: $1$1" > tmp.txt # Echo 1
if [ "$1" == "Oct" ]; then
echo "processed: 10"
else
echo "processed: $1$1" # Echo 2
fi
}
戻り値:
14-processed: OctOct-09:23:35 some other input
$1
Echo 2 に代入されていtmp.txt
ますが、値が含まれていますprocessed: \1\1
。後方参照がコマンド置換に挿入されていないかのように。さらに奇妙なことに、条件は!= "Oct" でif
失敗しますが、 = "Oct"を示すステートメントにフォールスルーします。$1
echo
$1
私の質問は、Echo 2 の場合に後方参照の挿入が機能するのに Echo 1 が機能しないのはなぜですか? 後方参照の挿入がまったく機能していないと思われます ( のif
ステートメントの失敗を考えるとTestFunc
) むしろ、Echo 2 の場合に置換が正しく機能しているように見える微妙なことが起こっています。その繊細さは何ですか?
解決
さらに考えてみると、何が起こっているのか理解していると思います。
\\1
コマンド置換サブルーチン/子関数にリテラルとして渡され\1
ます。これが、子関数内の等価テストが失敗する理由です。ただし、
echo
関数は\\1
文字列を として正しく処理しています$1
。soecho "aa$1aa"
は、コマンド置換の結果をsed
asに返しますaa\1aa
。その他の機能としてrev
「見る」$1
なども\1
。sed
次に、後方参照が何であれ補間\1
しaa\1aa
て、ユーザーに返します。Oct
aaOctaa
正規表現内のコマンド置換は明らかに機能するため、コマンド置換を実行する前に(または何でも)sed
の値を後方参照に置き換えると、非常にクールになります。これにより、sedのパワーが大幅に向上します...\\1
\1
$(...)