1

私の問題に対する利用可能な解決策を見落としていた場合に備えて、事前に謝罪しますが、これを理解するために数時間を費やしました:

混乱したログファイルがあります [私のせい T_T ではありません] 特定の文字列を含む行を見つける必要があります。この時点までは素晴らしくシンプルです。それらを見つけたら、「Before」[または String1 ] と「is」[または String2 ] という単語の間のすべてのスペースを別の char [私の場合はアンダースコア] に置き換える必要があります。「String1」の前または「String2」の後に来るものは影響を受けない可能性があります。

私が何をすべきかをあなたに伝えるために:

2012-08-27 00:14:55 1346019295409 Before Lorem ipsum dolor sit amet consectetuer Curabitur In id urna ut. Ut massa ac commodo commodo rutrum ac sit neque ante pede. is 47 ms

なる必要があります:

2012-08-27 00:14:55 1346019295409 Before_Lorem_ipsum_dolor_sit_amet_consectetuer_Curabitur_In_id_urna_ut._Ut_massa_ac_commodo_commodo_rutrum_ac_sit_neque_ante_pede._is 47 ms

タイムスタンプはほとんどすべてのエントリで異なるため、sed の制限を設定する方法を見つけようと考えていましたが、うまくいきませんでした...

誰かが私を正しい方向に向けてもらえますか?

4

4 に答える 4

2

あなたはできる。Sed はチューリング完全なので、何でもできます。これは、sed がその仕事に適したツールであることを意味するものではありません。sed コマンドに適切にマップされないものは、すぐに複雑になります。sed を主張する場合:

:a
s/\( Before .*\) \(.* is \)/\1_\2/
t a
s/ Before \(.*\) is / Before_\1_is /
s/ Before is / Before_is /

代わりに awk をお勧めします。コードは長くなりますが、ロジックは頭痛の種ほどではありません。

match($0, / Before (.* )?is /) {
    prefix = substr($0, 1, RSTART + 6);
    middle = substr($0, RSTART + 7, RLENGTH - 10);
    suffix = substr($0, RSTART + RLENGTH - 3);
    gsub(/ /, " ", middle);
    $0 = prefix + middle + suffix;
}
于 2012-08-27T21:55:37.173 に答える
2

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

sed 's/ /_/4g;s/_\([^_]*\)_\([^_]*\)$/ \1 \2/' file

説明:

  • s/ /_/4g4番目以降のスペースをスペースに置き換えます_
  • s/_\([^_]*\)_\([^_]*\)$/ \1 \2/'最後の 2 つ_の をスペースに置き換えます。

別の方法 (おそらくより_安全):

sed 's/\( [^ ]*\)\{2\}$/\n&/;h;s/\n.*//;s/ /_/4g;G;s/\n.*\n//' file

説明:

  • s/\( [^ ]*\)\{2\}$/\n&/最後の 2 つのスペースの前に改行を挿入する
  • hパターン スペース (PS) をホールド スペース (HS) にコピーします。
  • s/\n.*//最後の 2 つのスペースを含むパターンを削除します。
  • s/ /_/4gPS の最初の 4 つのスペースを除くすべてをアンダースコアに置き換えます。
  • G改行を追加し、その後に HS の内容を PS に追加します。
  • s/\n.*\n//文字列の元の最初の部分を削除します。
于 2012-08-28T05:41:32.860 に答える
1

これを行うためのよりエレガントな方法があるかもしれませんが、sed には多くのバージョンがあり、すべての優れた機能を備えた最新バージョンを持っているか、持っていない可能性があります。

したがって、各行の形式が同じである場合、最初の 3 つのスペースを一度に 1 つずつタブ文字に変換し (これは、データの使用方法に利点がある場合があります)、次に変換することです。他のすべてのスペースは「_」文字に。

 sed '
    s/ /      /
    s/ /      /
    s/ /      /
    s/ /_/g' file > newFile

編集して、行末に必要な2つのスペースを指摘してくれたDavid Yawのおかげで、それほど簡単ではないことがわかりました:-)。したがって、上記のスクリプトに次を追加できます。これも、実行したい置換の既知の数があるという考えに依存しています。ここで、最後の 2 つの「_」文字を見つけて、それらをスペースに置き換えます。

    '....
     s/\([^_][^_]*\)_\([^_][^_]*\)$/\1 \2/
     s/\([^_][^_]*\)_\([^_][^_]*\)$/\1 \2/' file > newFile

新しい sed は、グループをキャプチャするためにエスケープされた親を尊重しない場合があります。上記が機能しない場合は、各行から 4 つの「\」文字をすべて削除してみてください。

もちろん、置換パターンとして s/srchTarg/replPat/' の後半でタブ文字を取得するには、正しいことを行う必要があることに注意してください。vi エディターを使用している場合、Ctrl-V Ctrl-I (間にスペースを入れない) でタブ文字が挿入されます。もちろん、これは ControlV 文字 (Ctrl キーを押しながら V を押す) の後に Ctrl I (もう一度 Ctrl キーを押しながら I を押す) を意味します。Windows ベースのエディターからコピー ペーストする場合、タブ文字がスペースに変換されていると想定できるため、自分でこれに対処する必要があります。

また、タブの代わりに他の文字 (「:」や「|」など) を使用して、最後のステップとしてs/|/ /gそれらをスペースに戻すこともできます。

IHTH。

于 2012-08-27T21:12:31.683 に答える
1

Perlでやってみる

perl -ne '$_ =~ s/(?<=Before)(.*)(?=is)/$a=$1;$a=~s! !_!g; $a/e; print '

-e Perl で起動すると、一重引用符で囲まれたステートメントが実行されます。(?<=)肯定的な後読みです。それ以降のすべてに一致します。(?=)前向きな先読みです。その前のすべてに一致します。(.*)両方の間の文字列全体に一致し、一致を $1 に取り込みます。モディファイヤs///と一緒に使用します。これにより、Perl は Perl コードとしてe扱い、それを実行するようになります。/$a=$1;$a=~s! !_!g; $a

単に試してください:

echo "2012-08-27 00:14:55 1346019295409 Before Lorem ipsum dolor sit amet consectetuer Curabitur In id urna ut. Ut massa ac commodo commodo rutrum ac sit ne que ante petryde. is 47 ms" |
perl -ne '$_ =~ s/(?<=Before)(.*)(?=is)/$a=$1;$a=~s! !_!g; $a/e; print '
于 2012-08-27T23:06:59.333 に答える