역효과가있는 awk 시스템 호출

특정 키워드 사이에 여러 데이터 블록이 포함 된 데이터 파일이 있습니다 (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, blockname2blockname1_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}와 동일합니다.
  • 나는 ' 문자열이 유효한 인덱싱 변수이고 축소 된 if 문인지조차 알지 못합니다. 다시 한 번 감사드립니다. ' 슬프게도 " 허용 된 답변 "을 제공 할 수 없습니다. 이 접근 방식을 초기 작업을 수행 할 때 채택하려고하는데 ' 위의 질문에 대답하지 않습니다 (while 루프의 조건 해석).이 사이트에 대한 이해에 위배됩니다. Q & 시스템. 하지만 많은 것을 배웠습니다. 다시 한 번 감사드립니다.

답글 남기기

이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다