1

マッチしたパターンの前後6行をコメント(#)したい。この質問を参照しました。

sedを使用して、一致する行、その上と下の行を削除するにはどうすればよいですか?

このソリューションにホールド バッファを使用しようとしましたが、機能しませんでした。

ファイル内で次のシーケンスが複数回発生しています。

aaaa  
bbbb  
cccc  
dddd  
eeee  
ffff  
gggg  
hhhh  
iiii  
jjjj  
kkkk  
llll  
mmmm  
nnnn  
oooo  

を検索した場合hhhh、出力ファイルは以下のようになります。

  aaaa  
  #bbbb  
  #cccc  
  #dddd  
  #eeee  
  #ffff  
  #gggg  
  #hhhh  
  #iiii  
  #jjjj  
  #kkkk  
  #llll  
  #mmmm  
  #nnnn  
  oooo  

sedまたは他のスクリプトでこれを行うのを手伝ってください!!!

4

6 に答える 6

12

:help :global質問には Vim というタグが付けられています:help :normal

:g/hhhh/-6,+6norm I#

:substitute変異体:

:g/hhhh/-6,+6s/^/#

壊す:

  • この:globalコマンドは、指定されたパターンに一致する各行に対して Ex コマンドを実行するために使用されます。

    :g/hhhh/dを含むすべての行を削除しhhhhます。

  • Ex コマンドは通常、オプションの範囲を受け入れます。範囲には、絶対行番号、5,15および/または相対行番号を使用できます-3,+41

    :g/hhhh/-6,+6dを含むすべての行の上 6 行と下 6 行の間のすべてを削除しますhhhh

  • この:normalコマンドを使用すると、コマンドラインから通常のコマンドを実行でき、他の Ex コマンドと同様に範囲を受け入れます。は、行頭に aI#を挿入する最も簡単な方法で、コマンドラインから実行できます。これにより、最初の解決策が得られます。#:normal I#

    :g/hhhh/-6,+6norm I#
    
  • Ex コマンドとして、範囲も受け入れるので、範囲内の各行の先頭に:substitutea を挿入するためにも使用できます。これにより、2 番目のソリューションが得られます。#

    :g/hhhh/-6,+6s/^/#
    
于 2013-06-25T12:32:54.490 に答える
4

Perl でこれを行うには、ファイル全体を配列に読み取ってから、一致する行のインデックスを見つけ、周囲の行を編集する必要があります。これは範囲で行うことができます。

配列スライスから未定義の値を削除する必要があります。そうしないと、一致がファイルの先頭または末尾に近い場合 (つまり、6 行以内) に新しいエントリが作成されます。

perl -we '@a = <>;                      # read whole file
           for (0 .. $#a) {              # loop over indexes
               if ($a[$_] =~ /hhhh/) {   # find match
                   s/^/#/ for grep defined, @a[$_-6 .. $_+6]  # edit
               } 
           }; print @a" hhh.txt

for ループ$_では、要素にエイリアスが設定されているため、直接置換s///を適用できます。

これは、 を使用して簡略化することもできますTie::File

出力:

aaaa
#bbbb
#cccc
#dddd
#eeee
#ffff
#gggg
#hhhh
#iiii
#jjjj
#kkkk
#llll
#mmmm
#nnnn
oooo
于 2013-06-25T12:37:39.533 に答える
0

** ここに Perl ソリューションが登場!! **

コンテンツ全体を配列に格納し、配列を反復処理して、パターンが一致する場合は反復子変数にフラグを立てます。次に、イテレータ変数から 6 を削除して追加します。フラグが設定された変数が指定されている場合は、行の前にハッシュタグを連結できます。

より明確にするために:

use File::Slurp;
my $find_counter = 0;
my $line_counter = 0;
my @lines = read_file( 'filename' ) ;
foreach my $line (@lines) { # foreach or for loop
  if ($line =~ /$pattern/) {
    $file_counter = $line_counter;
    last;
  }
  $line_counter++;
}
# loop again through @lines and when the line is between
# $file_counter + - 6 , concat the hashtag in front of the line
于 2013-06-25T12:29:03.627 に答える
0

sed に慣れている人には、 を使用grepしてコンテキストをパイプで取得し、sedいくつかの簡単なsedコマンドを作成することをお勧めします。

grep -A6 -B6 -n hhhh file | sed -e 's/[^0-9].*$//' -e 's/$/s|^|#|/' | sed -f- file

(以下の例では、この出力の長さを短くするために-A1とがあります。)-B1

出力する一致する行の-A11 行後と1 行前に行番号を付けます。-B1grep -A1 -B1 -n hhhh file

7-gggg  
8:うーん  
9-iii  

...これを sed コマンドに変換して、番号付きの行を でコメントアウトし| sed -e 's/[^0-9].*$//' -e 's/$/s|^|#|/'ます。2 つの sed コマンドは、最初の非数字の後のすべてを削除し、その短縮された行の終わりを で| sed -e 's|^|#|'置き換えます。置換は、全体をコメントアウトします。ライン。それはこれを取得します:

7秒|^|#|
8秒|^|#|
9s|^|#|

...そして、これらのコマンドをsedにパイプしたいので、-f-which と同等のものを使用し-f /dev/stdin、sedにstdinからコマンドを読み取るように指示します。

grep -A1 -B1 -n hhhh abcd.txt | sed -e 's/[^0-9].*$//' -e 's/$/s|^|#|/' | sed -f- abcd.txt

ああああ  
bbbb  
cccc  
dddd  
ええええ  
フフフ  
#gggg   
#hhhh   
#iiii  
jjjj  
kkkk  
うーん  
んー  
んんん  
うーん  
于 2017-06-30T19:41:41.603 に答える