탄성파 패턴 코드의 출력을 설명하는 수천 줄이 포함된 파일이 있습니다. 파일의 크기는 빈도, 모델의 두께, 특정 모델에서 발견된 패턴 수에 따라 달라집니다. 헤더 정보에는 발견된 패턴 수가 포함됩니다. 모드는 0부터 N까지 번호가 매겨져 있으며 키워드 MODE 옆에 저장됩니다. 파일이 처음 두 패턴을 찾는 방법은 다음과 같습니다. 이 예에는 0부터 4까지 4가지 모드가 있습니다. "I DEPTH Y1 Y2 Y3 Y4" 레코드 뒤에는 진폭을 제공하는 1,000개 이상의 레코드가 이어집니다. 처음 두 모드에 대해서는 처음 두 레코드만 표시하고 있습니다. awk 및 모드 /MODE /를 사용하면 개별 MODE 번호를 쉽게 선택할 수 있습니다. 각 모드(mode_0, mode_1, ...)에 대해 해당 모드에 해당하는 1000개 정도의 값을 포함하는 별도의 파일을 만들고 싶습니다. 첫 번째 awk 호출을 사용하여 파일을 생성할 수 있지만, 첫 번째 awk 호출로 생성된 파일에 해당 패턴 진폭 값의 수천 개 정도의 기록을 가져올 수 없습니다. 실패한 시도는 두 번째 awk 호출이었습니다.
########## MODE NUMBER is " 0" (RAYLEIGH WAVE) ##########
I DEPTH Y1 Y2 Y3 Y4
1 3.000000E-01 9.999983E-01 1.166993E+06 -1.280462E-02 0.000000E+00
2 6.000000E-01 9.999933E-01 2.351593E+06 -2.580244E-02 0.000000E+00
This continues for a thousand or so records.
-1 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
########## MODE NUMBER is " 1" (RAYLEIGH WAVE) ##########
I DEPTH Y1 Y2 Y3 Y4 1 3.000000E-01 9.999960E-01 1.183126E+06 -1.280343E-02 0.000000E+00
2 6.000000E-01 9.999840E-01 2.367720E+06 -2.562274E-02 0.000000E+00
This continues for a thousand or so records.
-1 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
단일 모델의 마지막 행은 항상 마지막 레코드의 첫 번째 필드에서 -1로 끝납니다. 레코드 수는 가변적이며 일반적으로 1000개 이상입니다. 그런 다음 다음 패턴은 세 번째 레코드의 첫 번째 필드에서 1로 시작하고 패턴의 마지막 레코드의 첫 번째 필드에서 -1로 끝나는 이전 패턴과 정확히 동일한 형식으로 시작됩니다.
내가하려고했던 것은 다음과 같습니다.
- 각 모드에 대해 mode_0, mode_1, mode_2, ..., mode_N이라는 라벨이 붙은 별도의 파일을 만듭니다.
- 해당 mode_n 파일에 모드 진폭 값을 씁니다. 값은 "I DEPTH..." 라벨 아래의 부동 소수점 숫자입니다.
아래의 최근 시도에서 볼 수 있듯이 저는 awk에 대한 경험이 매우 부족합니다. 이 예에는 mode_0부터 mode_4까지 총 5개의 모드가 있습니다. awk에 대한 첫 번째 호출은 예상대로 작동하여 별도의 스키마 파일을 생성합니다. 두 번째 awk 호출은 다양한 스키마 파일에 값을 쓰려고 했던 많은 실패한 시도 중 하나였습니다. 또한 awk 범위 모드 /1/,/-1/을 시도했지만 작동하지 않았습니다. 나는 두 번째 awk 호출이 아래 나열된 모드 중 하나에서만 작동하도록 시도했지만 성공하지 못했습니다. 첫 번째 행의 첫 번째 필드에 "I"가 있는 레코드와 첫 번째 필드에 "-1"이 있는 마지막 레코드의 모드 진폭 값 사이의 모든 모드 진폭 값을 가져오는 방법을 알아내려고 합니다. 모달 진폭 부동 소수점은 음수일 수 있지만 "-1"은 엄밀히 말하면 정수이고 공백으로 둘러싸여 있으므로 각 개별 모달 진폭 값의 마지막 레코드를 검색하는 데 좋은 패턴이 됩니다.
gawk '/MODE / {
if($6 == "0\"" ) $6 = 0 # Remove double quotes from MODE 0" which only occurs for mode 0.
arr[i] = substr( $6,1,length($6-1))
{print $0 >> ("mode_"arr[i])}
}' inputfile
gawk '{ for (i = 1 ; i <= 4; i++)
if ( ( arr[i] == 0 ) &&
( $1 == " I " && $1 != " -1 ") )
print $0 >> ("mode_"arr[i])
}' inputfile
답변1
이 시도:
gawk '{
if ($1 == "##########") {
FS = "\"";
$0 = $0;
close(modefile);
modefile = "mode_"int($2);
FS = " "
} else {
if ($1 != "-1")
print $0 >> modefile
}
}' inputfile
답변2
귀하의 설명에 따르면 잘못된 것에 집중하고 계신 것 같습니다. "MODE NUMBER is" 모드는 출력 파일 이름을 검색하고 변경을 트리거하는 모드입니다. 다른 모든 내용은 현재 출력 파일에만 인쇄됩니다.
Perl에서 이를 수행하는 방법은 다음과 같습니다.
"MODE NUMBER is" 줄을 출력에 포함할지(또는 DEPTH, Y1, Y2, Y3, Y4가 포함된 필드 헤더 줄)를 원하는지 확실하지 않으므로 문을 추가했으며 다음과 같은 경우 주석 처리를 취소할 수 있습니다. 당신은 그것이 제외되기를 원합니다.
$ cat split-modes.pl
#!/usr/bin/perl
while (<<>>) {
# extract mode number, handling optional quote and leading spaces
if (/MODE NUMBER is "? *(\d+)/i) {
open($FH, ">", "mode_$1") || die "Couldn't open output file 'mode_$1': $!\n";
# uncomment next line to exclude the "MODE NUMBER is" line from the output
#next;
};
# Uncomment next line to exclude the "DEPTH Y1..Y4" header line
#next if (/^\s*I\s/);
print $FH $_;
}
또는 명령줄이나 쉘 스크립트 등에서 약간 단순화된 "한 줄짜리" 실행으로:
perl -n -e '
if (/MODE NUMBER is "? *(\d+)/i) {
open($FH, ">", "mode_$1");
next;
};
next if (/^\s*I\s*/);
print $FH $_;' inputfile
여기에는 거의 동일한 알고리즘이 있습니다 gawk
. 주요 차이점은 패턴 번호를 추출하려면 약간 더 많은 작업이 필요하다는 점이며, 더 이상 필요하지 않으면 awk에서 파일 핸들을 명시적으로 닫는 것이 일반적으로 좋은 생각입니다(이것은 perl 문에 의해 암시적으로 수행됩니다 open()
). 이는 파일을 내보낼 때 꼭 필요한 것은 아니지만 개발할 가치가 있는 좋은 습관입니다. Gawk 매뉴얼 섹션을 참조하세요.5.9 입력 및 출력 리디렉션 끄기
gawk '
/MODE NUMBER is/ {
# extract number(s) with 1-or-more digits in MODE line into array "a"
match($0,/[0-9]+/,a);
close(out);
# we are only interested in the first element of a
out = "mode_" a[0];
#next;
};
#/^[[:space:]]*I[[:space:]]/ { next };
{ print $0 > out }' inputfile
답변3
모든 Unix 시스템의 모든 쉘에서 awk를 사용하여 이것이 필요한 것 같습니다.
awk '/MODE/{close(out); out="mode_"(cnt++)} {print > out}' file
그러나 샘플 입력으로 1개의 레코드만 제공되며 예상되는 출력이 없습니다. 이는 테스트되지 않은 추측입니다.
업데이트된 예제 입력에서 빈 줄로 구분된 레코드로 표시되면 awk의 "단락 모드"(여전히 awk 사용)를 사용하여 다음을 처리하는 것이 더 간단할 것입니다.
awk -v RS= '{out="mode_"(NR-1); print > out; close(out)}' file
예를 들어:
$ cat file
########## MODE NUMBER is " 0" (RAYLEIGH WAVE) ##########
I DEPTH Y1 Y2 Y3 Y4
1 3.000000E-01 9.999983E-01 1.166993E+06 -1.280462E-02 0.000000E+00
2 6.000000E-01 9.999933E-01 2.351593E+06 -2.580244E-02 0.000000E+00
This continues for a thousand or so records.
-1 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
########## MODE NUMBER is " 1" (RAYLEIGH WAVE) ##########
I DEPTH Y1 Y2 Y3 Y4 1 3.000000E-01 9.999960E-01 1.183126E+06 -1.280343E-02 0.000000E+00
2 6.000000E-01 9.999840E-01 2.367720E+06 -2.562274E-02 0.000000E+00
This continues for a thousand or so records.
-1 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
$ awk -v RS= '{out="mode_"(NR-1); print > out; close(out)}' file
$ head mode_*
==> mode_0 <==
########## MODE NUMBER is " 0" (RAYLEIGH WAVE) ##########
I DEPTH Y1 Y2 Y3 Y4
1 3.000000E-01 9.999983E-01 1.166993E+06 -1.280462E-02 0.000000E+00
2 6.000000E-01 9.999933E-01 2.351593E+06 -2.580244E-02 0.000000E+00
This continues for a thousand or so records.
-1 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
==> mode_1 <==
########## MODE NUMBER is " 1" (RAYLEIGH WAVE) ##########
I DEPTH Y1 Y2 Y3 Y4 1 3.000000E-01 9.999960E-01 1.183126E+06 -1.280343E-02 0.000000E+00
2 6.000000E-01 9.999840E-01 2.367720E+06 -2.562274E-02 0.000000E+00
This continues for a thousand or so records.
-1 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00 0.000000E+00
답변4
마침내 이 문제를 해결했습니다. 다음과 같은 매우 간단한 스크립트가 바로 나에게 필요한 것입니다.
- 첫 번째 패턴은 패턴 번호가 포함된 레코드를 검색합니다.
- 두 번째 범위 패턴은 이름에 패턴 번호가 포함된 파일에 기록된 진폭 값의 시작과 끝을 정확하게 포함합니다.
- 패턴의 공백은 올바른 레코드를 가져오는 것을 보장합니다.
gawk '/MODE /{ if ($6 == "0\"" ) $6 = 0
modenum = substr( $6,1,length($6-1))
close(modefile)
modefile = "mode_"modenum
}
/ I /,/ -1 /{
print $0 >> modefile
}' infile