ファイルを解析し、特定の2行間のデータを印刷したいと思います。 「範囲開始」から「範囲終了」まで。ただし、「範囲の終わり」が存在する場合にのみ該当します。
ソースファイルが次の場合:
[This is the start] of some data
this is information
this is more information
This is does not contain the ending required
[This is the start] of some other data
this is info I want
this is info I want
[This is the ending I was looking for]
次のように印刷する必要があります。
[This is the start] of some other data
this is info I want
this is info I want
[This is the ending I was looking for]
grepを使用して必要なデータを見つけて上向きに印刷できましたが、行数は固定されていました。
データ行数が一定でない場合は、grepまたはsedを使用して最後の行から始めて、指定された文字列の次の項目を見つけて、目的の特定の範囲をキャプチャする方法はありますか?
データセグメントの「範囲の開始」は、「範囲の開始」と「範囲の終わり」ポイントの間のすべてのデータと一緒に印刷する必要があり、「範囲の終わり」の一致は行の範囲全体を印刷する必要があるかどうかを決定します。範囲(データセグメント)に指定された終わりがない場合は、印刷しないでください。複数のセグメントにエンドポイントがある場合は、エンドポイントを含むすべてのセグメントを印刷する必要があります。入力ファイルには終わりがありますが、開始がないか、単一の始動に複数の終わりがある場合はありません。
2つのパターンの間(および含む)の線を印刷します。一致する最初の行から印刷を開始し、最初の終了セグメントが見つかるまで印刷を続けるため、問題は解決されません。指定された出口ステートメントを含むセグメントのみを印刷する必要があります。
答え1
使用sed
:
$ sed -n '/This is the start/{h;d;}; H; /This is the ending/{x;p;}' file
[This is the start] of some other data
this is info I want
this is info I want
[This is the ending I was looking for]
注釈付きsed
スクリプト:
/This is the start/{ # We have found a start
h; # Overwrite the hold space with it
d; # Delete from pattern space, start next cycle
};
H; # Append all other lines to the hold space
/This is the ending/{ # We have found an ending
x; # Swap pattern space with hold space
p; # Print pattern space
};
このスクリプトが行うことは、すべての行を「予約済みスペース」(の共通バッファsed
)に格納することです。しかし、「スタートライン」を見つけたら、そのスペースをリセットします。 「終了行」が見つかると、保存されたデータが印刷されます。
「開始ライン」の前に「終了ライン」があり、間に「開始ライン」がない2つの「エンドライン」が見つかると、これは中断されます。
awk
上記と同じプロセスを実行するプログラムsed
:
$ awk '/This is the start/ { hold = $0; next }
{ hold = hold ORS $0 }
/This is the ending/ { print hold }' file
(上記と同じ出力)
答え2
複数START
とEND
パターンの場合は、次のことができます。
sed 'H;/START/h;/END/!d;x;/START/!d' infile
これは、前のバッファに無条件に行を蓄積し、H
行が見つかるたびにそれを上書きし(つまり、最新の行のデータのみを保持し)、行が含まれていない場合はパターンスペースを削除し(ここでループを再開します)そうでなければe変更バッファを削除し、パターン空間を再び削除します。今回は、パターンスペースが含まれていない場合、残りは自動的に印刷されます。h
START
START
d
END
x
d
START
答え3
tac
行の順序を変更するために使用されます。
ファイルを反転する場合tac
(最後の行を最初に印刷するなど)、終了パターンから開始パターンまで領域を抽出できます。その後、tac
再び使用して出力ラインを順方向に印刷します。
tac file.txt | awk '/^\[This is the ending I was looking for]/,/^\[This is the start]/ { print $0 }' | tac
画面に合うようにフォーマットされた同じコード:
tac file.txt | \
awk '/^\[This is the ending I was looking for]/,/^\[This is the start]/ { print $0 }' | \
tac
{ print $0 }
awk
デフォルト動作なので、この特定のコマンドには必要ありません。
tac file.txt | \
awk '/^\[This is the ending I was looking for]/,/^\[This is the start]/' | \
tac
残念ながら、Macを使用している場合、デフォルトではtac
インストールされません。
答え4
awkを使用するソリューションは次のとおりです。
rstart='^[[]This is the start[]]'
rend='[[]This is the ending I was looking for[]]'
awk '$0~rstart{i=1;a=""}
$0~rstart,$0~rend && i==1 {a = a ((a=="")?"":ORS) $0}
$0~rend{i=0;print(a)}
' rstart="$rstart" rend="$rend" infile
角かっこはバックスラッシュの使用を防ぐため[[]
に、と一致します(場合によっては失敗する可能性があります)。[]]
\\[
主なアイデアは、変数i
(含む)をブール値として使用して、印刷する範囲の各行を含めるか除外することです。全範囲は変数に蓄積されますa
。変数がa
空でない場合(((a=="")?"":ORS)
)出力レコード区切り記号(ORS)で区切られます。
これにより、次のものが印刷されます。
[This is the start] of some other data
this is info I want
this is info I want
[This is the ending I was looking for]
要件が開始タグと終了タグを印刷しない場合は、同じコードを使用しますが、行1と3を置き換えます。
awk '$0~rend{i=0;print(a)}
$0~rstart,$0~rend && i==1 {a = a ((a=="")?"":RS) $0}
$0~rstart{i=1;a=""}
' rstart="$rstart" rend="$rend" infile
以下を印刷します。
this is info I want
this is info I want