특정 키워드 사이에 여러 데이터 블록이 포함 된 데이터 파일이 있습니다 (DATA
, END
). 저는 awk
를 사용하여 해당 블록에서 가져온 파일 이름을 기반으로 데이터 블록을 별도의 파일로 추출합니다. 일부 데이터 블록은 동일한 이름을 공유하므로 파일 ( “blockname
“)이 이미 존재하는 경우 증가하는 정수로 각 출력 파일의 이름을 변경합니다.
#cat input.file useless stuff1 DATA blockname1 data1 data1 END useless stuff2 DATA blockname2 data2 data2 END useless stuff3 DATA blockname1 data3 data3 END useless stuff4
예상되는 출력 파일은 3 개입니다. blockname1
, blockname2
및 blockname1_1
(마지막 파일에 정수가 할당 된 방식에 유의하세요.)
#cat blockname1 DATA blockname1 data1 data1 END
(다른 파일은 그에 따라 …)
이제 다음 스크립트가 원하는대로 작동합니다.
awk "BEGIN { FS=" +" } ; \ /DATA/,/END/ \ { if ( $1 ~ /DATA/ ) \ { block=$2 ; i=0 ; file=block ;\ while ( system("test ! -e " file ) ) \ { i++ ; file=block"_"i ; print file } \ } ; \ print $0 > file \ } " \ input.file
내 문제는 while
루프에 있으며 시스템 호출 :
file
가 존재하면 system("test -e " file)
가 TRUE이고
는 아직 존재하지 않습니다. 즉, file
가 있고 file
가있는 경우에만 실행을 시작하는 while
루프 (새로운) file
가 아직 존재하지 않는 경우 중단합니다.
그러나 (그리고 print file
를 사용하여 상세하게 만드십시오), 정수 접미사가 증가하는 동일한 이름의 무한 루프가 있고 반대 system("test !-e " file)
는 원하는 결과를 제공합니다.
그래서 이것은 내가 기대했던 것과 정확히 반대로 작동합니다.
답변
좋아요. 문제는 test
의 종료 상태와 while
awk
의 루프 조건.
포지티브 test
명령은 , FALSE의 경우 1
에서 마이너스입니다.
그러나 awk
while
루프는 0
를 FALSE로, 1
를 TRUE로 해석하므로 정확히 반대입니다. 정의.
예 :
awk "{ while ( 0 ) ; { print "0" } }" file
프로가 아닙니다. 출력을 유도하는 반면
awk "{ while (1) ; { print "1" } }" file
는 무한한 1
를 인쇄합니다.
모범 사례 따라서 이러한 조합에서
while ( system("command") == 0 )
또는
while ( system("command") == 1 )
각각으로 명시해야합니다.
제 경우에는
while ( system("test -e " file ) == 0 )
예상되는 동작을 보여줍니다.
답변
awk
system()
는 실행 한 명령의 종료 상태를 반환합니다. 성공의 경우 0이고! = 성공하지 않으면 0. 간단한 예를 들면 다음과 같이 실행할 수 있습니다.
v = system("date");
v는 0이됩니다
실행하는 경우 :
v = system("dat");
v는 127이거나 0과 다른 값일 수 있습니다. dat 명령이 없거나 찾을 수없는 경우 OS에서 오류가 반환됩니다.
답변
내가 이해한다면 목표는 input.file의 내용을 같은 이름의 블록 손실을 방지하는 다양한 파일로 추출하는 것입니다.
그렇다면 추출하기 전에 대상 디렉토리가 항상 비어있는 경우 더 나은 (그리고 더 빠른) 솔루션이 있습니다.
awk " /DATA/{ block=$2; n = blocks[block]++; file=block (n? "_" n: ""); } /DATA/,/END/{ print > file }" input.file
이런 식으로 awk는 “파일이 존재하는지 테스트하기 위해 새 셸을 N 번 실행할 필요가 없습니다.
참고 :
- awk의 필드 구분자 때문에 BEGIN 블록이 필요하지 않습니다. 은 (는) 이미 공백입니다.
- 작은 따옴표가 이미 여러 줄이므로 줄 끝에
"\"
가 필요하지 않습니다.
while
조건의 " odd " 동작을 더 잘 이해했습니다. 그러나 귀하의 솔루션은 매우 깔끔합니다. 고맙습니다. 부피가 큰 것보다 이것을 선호합니다. BEGIN 블록은 다른 파일 형식에서 남은 것입니다. 일반적인 예제에서는 쓸모가 없다는 것을 잊었습니다. 백 슬래시를 생략하면 문제가 발생하지 않습니다. 이것도 감사합니다. 하지만 스크립트의 의도는 '입니다.n = blocks[block]++; file=block (n? "_" n: "")
부분에 대해 좀 더 자세히 설명해 주시겠습니까?blocks
하나의 배열을 사용합니다. 블록 이름으로. 전의."blockname1"
의 첫 번째 인스턴스 :blocks["blockname1"]
. Awk는 해당 인덱스를 찾고 ' 찾지 못하기 때문에""
(0으로 간주 됨)를 가정합니다. 이제 awk에서n = var++
는{n=var;var++}
와 동일하므로n==""
및blocks["blockname1"]==1
.마지막으로file=block (n? "_" n: "")
는{file=block;if(n!="") file+="_" n}
와 동일합니다.