2

次のような文字列が与えられた場合、 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

この場合、sedwithTestFuncは次の出力を生成します。

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

$1Echo 2 に代入されていtmp.txtますが、値が含まれていますprocessed: \1\1。後方参照がコマンド置換に挿入されていないかのように。さらに奇妙なことに、条件は!= "Oct" でif失敗しますが、 = "Oct"を示すステートメントにフォールスルーします。$1echo$1

私の質問は、Echo 2 の場合に後方参照の挿入が機能するのに Echo 1 が機能しないのはなぜですか? 後方参照の挿入がまったく機能していないと思われます ( のifステートメントの失敗を考えるとTestFunc) むしろ、Echo 2 の場合に置換が正しく機能しているように見える微妙なことが起こっています。その繊細さは何ですか?

解決

さらに考えてみると、何が起こっているのか理解していると思います。

  • \\1コマンド置換サブルーチン/子関数にリテラルとして渡され\1ます。これが、子関数内の等価テストが失敗する理由です。

  • ただし、echo関数\\1文字列を として正しく処理しています$1。soecho "aa$1aa"は、コマンド置換の結果をsedasに返しますaa\1aa。その他の機能としてrev「見る」$1なども\1

  • sed次に、後方参照が何であれ補間\1aa\1aaて、ユーザーに返します。OctaaOctaa

正規表現内のコマンド置換は明らかに機能するため、コマンド置換を実行するに(または何でも)sedの値を後方参照に置き換えると、非常にクールになります。これにより、sedのパワーが大幅に向上します...\\1\1$(...)

4

2 に答える 2

1

これはうまくいくかもしれません(GNU sed):

s/$/\nJan01...Oct10Nov11Dec12/;s/(...) (..) (..:..:.. .*)\n.*\1(..).*/\2-\4-2013 \3/;s/\n.*//' file

行末にルックアップを追加し、後方参照を使用して照合し、すべての場合にルックアップ テーブルを削除するようにします。

関数に後方参照を渡す例を次に示します。

f(){ echo "x$1y$1z"; }
echo a b c | sed -r  's/(.) (.) (.)/'"$(f \\2)"'/'

戻り値:

xbybz

HTH

于 2013-10-14T20:38:34.250 に答える
1

適切なツールを使用してください:

date -d "Oct 14 09:23:35" +"%d-%m-%Y %H:%M:%S"
14-10-2013 09:23:35

日付は入力を読み取り、好きな形式に変換します

于 2013-10-14T17:01:07.427 に答える