다음과 같은 파일이 있습니다.
예.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
두 번째 일치 항목은 첫 번째 일치 항목 이후에 정확하게 인쇄되는 것을 볼 수 있습니다(줄 바꿈이나 구분 기호 없음). 이러한 이벤트를 파일로 분리할 수 없습니다.
원하는 출력은 다음과 같습니다.
파일 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
또는 전체 파일을 전체적으로 가져와 정규식을 사용하는 대신 한 줄씩 읽으십시오.
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부터 시작하는 두 자리 숫자가 옵니다.--suppress-matched
- 패턴( )과 일치하는 줄을 억제합니다/^ \{4\}-1$/
.- 이는 분할이 패턴별로 수행되기 때문에 필요합니다
csplit
(첫 번째 줄과 마지막 줄을 알 수 없으며 패턴은 하나만 있습니다). 따라서 각 "꺼진" 패턴 후에는 해당 패턴만 포함하는 파일이 생성됩니다. 아래에서 다시 분할됩니다). 모드를 억제하는 경우 다음 플래그를 사용하여 이를 방지할 수 있습니다.
- 이는 분할이 패턴별로 수행되기 때문에 필요합니다
-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
예제에서 위 명령을 실행하면 다음 내용이 포함된 두 개의 파일이 생성됩니다.
$ 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