次のファイルがあります。
はい.txt
-1
15
1 0 0 11 -1.0000E+001 1.0000E+001 -1.0000E+001
2 0 0 11 1.0000E+001 1.0000E+001 -1.0000E+001
...
29 0 0 11 1.0000E+001 2.0000E+001 1.0000E+001
30 0 0 11 5.0000E+000 5.0000E+000 5.0000E+000
-1
#ffafsda
-1
780
1 116 1 2 1 1 7 20
1 11 2 15 4 18 3 12
13 16 22 19 5 24 9 29
8 27 6 23
-1
asfasd
afsdasdf
常に正確に一致する行で始まり終わるブロックで構成されています^ {4}-1$
。このチャンクでファイルを複数に分割する必要があります。
私が今考えているのは、これらの塊を抽出する複数行の正規表現です。
grep -Pzo '(?s)((?m:^)\s{4}-1(?m:$).*?(?m:^)\s{4}-1(?m:$))' example.txt
出力:
-1
15
1 0 0 11 -1.0000E+001 1.0000E+001 -1.0000E+001
2 0 0 11 1.0000E+001 1.0000E+001 -1.0000E+001
...
29 0 0 11 1.0000E+001 2.0000E+001 1.0000E+001
30 0 0 11 5.0000E+000 5.0000E+000 5.0000E+000
-1 -1
780
1 116 1 2 1 1 7 20
1 11 2 15 4 18 3 12
13 16 22 19 5 24 9 29
8 27 6 23
-1
2番目の一致は、最初の一致の後に正確に印刷されることがあります(改行や区切り文字なし)。これらのイベントをファイルに分割することはできません。
希望の出力は次のとおりです。
ファイル1:
-1
15
1 0 0 11 -1.0000E+001 1.0000E+001 -1.0000E+001
2 0 0 11 1.0000E+001 1.0000E+001 -1.0000E+001
...
29 0 0 11 1.0000E+001 2.0000E+001 1.0000E+001
30 0 0 11 5.0000E+000 5.0000E+000 5.0000E+000
-1
ファイル2
-1
780
1 116 1 2 1 1 7 20
1 11 2 15 4 18 3 12
13 16 22 19 5 24 9 29
8 27 6 23
-1
助けてくれてありがとう。
答え1
-z
(非標準 GNU 拡張)、NUL で区切られたレコードで動作しますが、そうではgrep
ありません。複数行 grep、だから:
- 一致は、NULで区切られた各レコードに対して独立して実行されるか、区切りがない場合は完全な入力で実行されます(未区分のレコードを使用する機能は別のGNU拡張です)。
- (
-o
別の非標準GNU拡張)各一致に対してNULで区切られた出力
したがって、出力の記録ははい別途(実際には分離)。sed -n l
たとえば、出力を渡すと、次のようになります。
$ grep -Pzo '(?s)((?m:^)\s{4}-1(?m:$).*?(?m:^)\s{4}-1(?m:$))' example.txt | sed -n l
-1$
15$
1 0 0 11 -1.0000E+001 1.0000E+001 -1\
.0000E+001$
2 0 0 11 1.0000E+001 1.0000E+001 -1\
.0000E+001$
...$
29 0 0 11 1.0000E+001 2.0000E+001 1\
.0000E+001$
30 0 0 11 5.0000E+000 5.0000E+000 5\
.0000E+000$
-1\000 -1$
780$
1 116 1 2 1 1 \
7 20$
1 11 2 15 4 18 \
3 12$
13 16 22 19 5 24 \
9 29$
8 27 6 23$
-1\000$
\000
各一致を区別するsを確認してください。
ここで一致を単純化できます。
grep -Pzo '(?sm)(^\s{4}-1$).*?(?1)' example.txt
grep
ただし、これを使用する代わりに-P
(P
erlの非標準GNU拡張でもある)、実際に使用することができます。これにはいくつかの利点があります。
- PerlはGNU grepよりも多くのシステムに存在するため、移植性が高くなります(Perlと同様の正規表現サポートがGNUビルドで常に有効になるわけではありません
grep
)。 - Perlは
-0
NULで区切られたレコードを使用する必要がありますが、これはあなたが望むものではありません。あなたはフルルックを飲むモードが欲しいですperl
。-0777
- Perlは独自に別々のファイルに出力を書き込むことができます。
perl -l -0777 -ne '
while (/(^\s{4}-1$).*?(?1)/msg) {
open OUT, ">", "output-" . ++$n . ".txt" or die;
print OUT $&
}' example.txt
または、ファイル全体を完全にインポートし、正規表現を使用する代わりに1行ずつ読みます。
perl -ne '
if (/^\s{4}-1$/) {
if ($inside = 1 - $inside) {
open OUT, ">", "output-" . ++$n . ".txt" or die;
} else {
print OUT; next
}
}
print OUT if $inside' example.txt
(すべて一致しなくても別の結果が表示されます-1
)。
1これについては、GNUがオプションとして使用する(利用可能な)PCRE2に付属のサンプルアプリケーションpcre2grep -M
(以前のpcregrep -M
)を参照してください。pcre2grep
grep
-P
答え2
代わりに、全体の塊を得る別の方法grep
まず、次のようにsed
生成することをお勧めします。
sed -n '/^ \{4\}-1$/,/^ \{4\}-1$/p' example.txt
-1
15
1 0 0 11 -1.0000E+001 1.0000E+001 -1.0000E+001
2 0 0 11 1.0000E+001 1.0000E+001 -1.0000E+001
...
29 0 0 11 1.0000E+001 2.0000E+001 1.0000E+001
30 0 0 11 5.0000E+000 5.0000E+000 5.0000E+000
-1
-1
780
1 116 1 2 1 1 7 20
1 11 2 15 4 18 3 12
13 16 22 19 5 24 9 29
8 27 6 23
-1
チャンクを別のファイルに分割
その後利用できますcsplit
コマンドはパターンに従ってファイルを分割します。
名前
csplit
- ファイルをコンテキストラインによって決定された部分に分割する要約
csplit
[オプション]...ファイルモード...説明する
PATTERNで区切られたFILEフラグメントを「xx00」、「xx01」、...ファイルに出力し、各フラグメントのバイト数を標準出力に出力します。
はい
$ sed -n '/^ \{4\}-1$/,/^ \{4\}-1$/p' example.txt | csplit - -f example --suppress-matched -z '/^ \{4\}-1$/' '{*}'
331
292
説明する:
csplit -
- 標準入力から読み出します。-f example
- ファイルのプレフィックスを「example」に設定します(デフォルトは「xx」の代わりに)。各プレフィックスの後には、00から始まる2桁の数字が続きます。--suppress-matched
- パターン()に一致する行を抑制します/^ \{4\}-1$/
。- これは、分割がパターンごとに行われるために必要です
csplit
(最初の行と最後の行は不明で、パターンは1つだけです)。したがって、各「オフ」パターンの後、そのパターンのみを含むファイルが生成されます。下から再分割されます)。モードを抑制する場合は、次のフラグを使用してこれを回避できます。
- これは、分割がパターンごとに行われるために必要です
-z
- 空の出力ファイルを削除'/^ \{4\}-1$/'
- パターンはファイルを分割する場所を示します。'{*}'
- 前のパターンをできるだけ繰り返します。
生成されるすべてのファイルのサイズを出力します。
結果:必要なブロックがあるがパターンがない2つのファイル。
$ cat example00
15
1 0 0 11 -1.0000E+001 1.0000E+001 -1.0000E+001
2 0 0 11 1.0000E+001 1.0000E+001 -1.0000E+001
...
29 0 0 11 1.0000E+001 2.0000E+001 1.0000E+001
30 0 0 11 5.0000E+000 5.0000E+000 5.0000E+000
$ cat example01
780
1 116 1 2 1 1 7 20
1 11 2 15 4 18 3 12
13 16 22 19 5 24 9 29
8 27 6 23
ファイルに区切られた行(最初の行と最後の行)を返すには、-1
次のコマンドを使用します。
sed -i '1s/.*/ -1\n\0/; $s/$/\n -1/' example[0-9][0-9]
--suppress-matched
と-z
表示の詳細な説明
説明のために--suppress-matched
何が起こるかをお見せしましょう。
$ sed -n '/^ \{4\}-1$/,/^ \{4\}-1$/p' example.txt | csplit -f example -z - '/^ \{4\}-1$/' '{*}'
338
7
299
7
4つのファイルが作成されます。パターンexample01
のみが含まれていますexample03
。
$ cat example00
-1
15
1 0 0 11 -1.0000E+001 1.0000E+001 -1.0000E+001
2 0 0 11 1.0000E+001 1.0000E+001 -1.0000E+001
...
29 0 0 11 1.0000E+001 2.0000E+001 1.0000E+001
30 0 0 11 5.0000E+000 5.0000E+000 5.0000E+000
$ cat example01
-1
$ cat example02
-1
780
1 116 1 2 1 1 7 20
1 11 2 15 4 18 3 12
13 16 22 19 5 24 9 29
8 27 6 23
$ cat example03
-1
使用すると、--suppress-matched
-1のある行が抑制され、結果は空であるためexample01
生成example03
されません。
答え3
正規表現を「行」を定義するレコード区切り文字として使用できるようにするGNU awkを使用できます。ここでは に設定できます\n -1\n
。これは改行文字1個、スペース4個-1
、改行文字1個です。その後、目的のセクションの始めと終わりに表示されるため、本質的に他のすべての「行」が必要になるため、行番号モジュールで2が0のときに印刷できます。
gawk '
BEGIN{
RS="\n -1\n";
ORS=RS
}
NR % 2 ==0 { print RS $0 > "outfile." ++c }' file
例では、上記のコマンドを実行すると、次の内容を含む2つのファイルが生成されます。
$ ls
file outfile.1 outfile.2
$ cat outfile.1
-1
15
1 0 0 11 -1.0000E+001 1.0000E+001 -1.0000E+001
2 0 0 11 1.0000E+001 1.0000E+001 -1.0000E+001
...
29 0 0 11 1.0000E+001 2.0000E+001 1.0000E+001
30 0 0 11 5.0000E+000 5.0000E+000 5.0000E+000
-1
$ cat outfile.2
-1
780
1 116 1 2 1 1 7 20
1 11 2 15 4 18 3 12
13 16 22 19 5 24 9 29
8 27 6 23
-1
これは、各ファイルの先頭に空行を追加する不幸な副作用があります。これが問題の場合は、-1
明示的な内容を印刷するだけです。
gawk '
BEGIN{
RS="\n -1\n";
}
NR % 2 ==0 { printf " -1\n%s\n -1\n", $0 > "outfile." ++c }' file
答え4
awkを使用してください。
$ cat tst.awk
/^ -1/ {
if ( inBlock ) {
print > out; close(out)
}
else {
out = FILENAME "_" (++cnt)
}
inBlock = !inBlock
}
inBlock { print > out }
$ awk -f tst.awk example.txt
$ head example.txt_*
==> example.txt_1 <==
-1
15
1 0 0 11 -1.0000E+001 1.0000E+001 -1.0000E+001
2 0 0 11 1.0000E+001 1.0000E+001 -1.0000E+001
...
29 0 0 11 1.0000E+001 2.0000E+001 1.0000E+001
30 0 0 11 5.0000E+000 5.0000E+000 5.0000E+000
-1
==> example.txt_2 <==
-1
780
1 116 1 2 1 1 7 20
1 11 2 15 4 18 3 12
13 16 22 19 5 24 9 29
8 27 6 23
-1