2010-12-14 10 views
6

行の特定の部分だけでsedを動作させるにはどうすればよいですか?そして、逆に、行の特定の部分でsedを動作させないようにするにはどうすればよいですか?一部の行のみを操作する方法

例:

"A a A a (A a) A (a A) a" 

私は、例えば、取得するためにT()間のみをすべてA Sを交換するにはどうすればよい:

"A a A a (T a) A (a T) a" 

そして、与えられた次の例入力:

"F f F f (F f) F (f F) f" 
私は、例えば、取得 に Xのが、 ()ないですべて F Sを交換するにはどうすればよい

「X F X F(FのF)Xを(F F) f "

私はGoogleを検索しましたが、使用できるものは見つかりませんでした。私はsedに関する一般的な質問だと思います。問題は、一般的なsedの "テンプレート"に還元されます。

  1. を有し、かつ、その後(特定のライン上のすべての出現に)のみ、それらの間に動作するよう
  2. を有し、かつ他のどこよりも、それらの間に作動するように...
  3. FROMとTOはある特殊なケース同じように、それはすべての操作だけでなく、置換基を有するが、また、印刷等で動作するはずの両方1.と2.

ため (「と」または「FOO」と「FOO」などの間)文字列の中の文字列 "FOO"と "BAR"の間のすべてを印刷します。

"1 2 3 BAR a b c FOO d e f BAR g a h FOO i j k BAR l m n FOO o p q" 

結果はそう

" d e f i j k " 

なり、それを行う方法についての一般的な例は非常にいただければ幸いです。この質問はかなり一般的だと思われますが、Googleではまだいいハウツーは見つかりません。私もこの が答えに挑戦するだろうと思います。 Perl、AWK、またはsed以外のものを使用してください。この質問は本当にsed-onlyな質問です。

+0

私はベストを尽くしました。私のアイデアはFROMとTO(何とか)でラインを分割し、偶数パートか奇数パートかどちらかで同様に動作するように(何とか)わかっています。私がそれをする方法を知っていたら、私はここで尋ねなかったでしょう。そして、私の考え方は間違っている可能性が高いです。それはかなり難しく、以前は単純なタスクでsedを使用していました。 – mjf

答えて

1

分裂と征服。

セグメントを区切るために改行を挿入し、アンカーとループとして改行、行の先頭(^)、行の終わり($)と区切り文字(この場合は括弧)を使用します。追加された改行は最後に削除されます。

$ echo "A a A a (A a) A (a A) a" | 
    sed 's/([^)]*)/\n&/g; 
     :a; 
      s/\(\n([^)]*\)A\([^)]*)\)/\1T\2/; 
     ta; 
     s/\n//g' 
A a A a (T a) A (a T) a 
$ echo "F f F f (F f) F (f F) f" | 
    sed 's/(/\n(/g; 
     s/)/)\n/g; 
     :a; 
      s/\([^(]*\)F\([^)]*\(\n\|$\)\)/\1X\2/g; 
     ta; 
     s/\n//g' 
X f X f (F f) X (f F) f 
$ echo "1 2 3 BAR a b c FOO d e f BAR g a h FOO i j k BAR l m n FOO o p q" | 
    sed 's/^/BAR/; 
     s/$/FOO/; 
     s/FOO/&\n/g; 
     s/BAR/\n&/g; 
     s/BAR[^\n]*\n//g; 
     s/[^\n]*FOO\n//g; 
     s/\n//g' 
d e f i j k 
+0

ありがとうございます。私にそれを通過する時間を与えてください。 – mjf

+0

"["と "]"文字で囲まれたセクションのすべてを、正規表現と同じように置き換えたい場合はどうすればよいですか?この作業は正規の正規表現(grepやsed式のように特殊な文字をエスケープする必要がある場合は、すべての "(){} {+?"文字をエスケープする必要はありません)を変換するのと似ています。つまり、sed構文でエスケープしなければならない文字をエスケープせずに次のsed式を指定すると、次のsedプログラムのAROUNDスペースに適用したい特殊文字にするためです。 "s/\\([] [( ){} | +?] \\)/ \\\ 1/g "となります。入力は同じs /([] [(){} | +?])/ \\\ 1/g "となります。 – mjf

+0

BASIC POSIX regexesのデータベースは、 "^。[$()| * +?{\"文字を "\"でエスケープして非特殊(man 7 regex)にする必要がある形式で維持します。私はこれらの正規表現をある時点で必要とする形式、例えばgrep(1)形式に変換するためのスクリプトが必要です。次に、sed(1)形式やviエディタ形式などが必要です。手作業で正規表現を変換するのは辛いですし、現在はdbがかなり大きなサイズになっています。 viのような巧妙なエディタであっても、手作業ですべての正規表現を変換するには苦労します。私はその仕事のためのスクリプトが必要で、これはこの質問をするための私の元の動機でした。 – mjf

1

あなたは(GNUのSED)のためにこれはうまくいくかもしれない:

sed ':a;s/\(([^)]*\)A/\1T/;ta' file # for case 1 

sed ':a;s/\(([^)]*\)F/\1\n/;ta;y/F\n/TF/' file # for case 2 

s 'はTへの内部の括弧' はAを置換する場合1つの使用Forループ。それぞれX年代とF年代にSと改行「のF翻訳次に、改行に括弧内のS」のFを変更するには、上記と同じケース2の使用のため

ケース3は、もう少し複雑ですが、2つの代替コマンドで行うことができます

sed -r 's/FOO|BAR/\n&/g;s/[^\n]*(\nBAR[^\n]*)*(\nFOO([^\n]*)\nBAR)?(\nFOO[^\n]*$)?/\3/g' file 

まず接頭改行と各FOOBAR文字列。 FOOBARのすべての組み合わせを探し、文字列をFOOBARの間に保ちます。改行では、負のクラスを使用して手続きを簡素化できます。

関連する問題