파일 이름에 =가 포함 된 경우 awk가 멈추고 기다리는 이유는 무엇입니까?


답변:


19

크리스는 말한다 , 형태의 인수 variablename=anything합니다 ((이상) 반대로 인수가 처리되는 시간에 수행되는 변수 할당으로 처리됩니다 -v var=value전과 수행하는 사람 BEGIN문) 대신 입력 파일 이름.

다음과 같은 경우에 유용 할 수 있습니다.

awk '{print $1}' FS=/ RS='\n' file1 FS='\n' RS= file2

파일마다 다른 FS/를 지정할 수 있습니다 RS. 그것은 또한 일반적으로 사용됩니다 :

awk '!file1_processed{a[$0]; next}; {...}' file1 file1_processed=1 file2

다음 중 더 안전한 버전입니다.

awk 'NR==FNR{a[$0]; next}; {...}' file1 file2

( file1비어 있으면 작동하지 않습니다 )

그러나 이름에 =문자 가 포함 된 파일이 있으면 방해가됩니다 .

이제 첫 번째 남은 =것이 유효한 awk변수 이름 일 때만 문제가됩니다 .

유효한 변수 이름을 구성하는 awk것이보다 엄격 sh합니다.

POSIX는 다음과 같아야합니다.

[_a-zA-Z][_a-zA-Z0-9]*

휴대용 문자 집합의 문자 만 그러나 /usr/xpg4/bin/awkSolaris 11 이상은 최소한 그 점을 준수하지 않으며 a-zA-Z뿐만 아니라 변수 이름의 로켈에서 알파벳 문자를 허용합니다.

같은 인수 그래서 x+y=foo=bar또는이 ./foo=bar무엇을하는 것은의 남아로 여전히 입력 파일 이름이 아닌 과제로 처리됩니다 첫번째 =유효한 변수 이름이 아닙니다. 구현 및 로케일 Stéphane=Chazelas.txt에 따라 같은 인수가 있을 수도 있고 아닐 수도 있습니다 awk.

그래서 awk에서는 다음을 사용하는 것이 좋습니다.

awk '...' ./*.txt

대신에

awk '...' *.txt

예를 들어 txt파일 이름에 =문자 가 포함되어 있지 않다고 보장 할 수없는 경우 문제를 피하기 위해 .

또한 -vfoo=bar.txt다음을 사용하는 경우 와 같은 인수 가 옵션으로 취급 될 수 있습니다.

awk -f file.awk -vfoo=bar.txt

(또한 적용 awk '{code}' -vfoo=bar.txtawk비지 버전 1.28.0 사전을 참조 버그 리포트에 대응 ).

다시 말하지만, 그 문제를 ./*.txt해결하면 ./접두사를 사용하면 표준 입력 을 의미 -하는 것으로 awk이해 되는 파일이 도움이 됩니다.

그 이유도

#! /usr/bin/awk -f

shebangs는 실제로 작동하지 않습니다. 그동안 var=value사람에 의해 해결할 수있는 고정ARGV 값 (A 추가 ./A의 접두사를) BEGIN문 :

#! /usr/bin/awk -f
BEGIN {
  for (i = 1; i < ARGC; i++)
    if (ARGV[i] ~ /^[_[:alpha:]][_[:alnum:]]*=/)
      ARGV[i] = "./" ARGV[i]
}
# rest of awk script

스크립트가 awk아닌 옵션으로 볼 수 있으므로 옵션 옵션에는 도움이되지 않습니다 awk.

그 사용과 함께 하나의 잠재적 인 화장품 문제 ./접두사는에 끝입니다 FILENAME,하지만 당신은 항상 사용할 수 있습니다 substr(FILENAME, 3)당신이 그것을 원하지 않는 경우를 제거 할 수 있습니다.

GNU 구현은 옵션으로 awk모든 문제를 해결합니다 -E.

이후 -Egawk는 awk스크립트 의 경로 ( -여전히 stdin을 의미 함)와 입력 파일 경로의 목록 만 예상합니다 ( -특별히 다루지 않음 ).

다음을 위해 특별히 설계되었습니다.

#! /usr/bin/gawk -E

인수 목록은 항상 입력 파일 (당신이 편집에 무료로 아직도 있습니다 있습니다 shebangs ARGVA의 목록 BEGIN문).

다음과 같이 사용할 수도 있습니다.

gawk -e '...awk code here...' -E /dev/null *.txt

우리는 사용 -E빈 스크립트 (로 /dev/null단지 있는지 그 수 있도록) *.txt가 포함 된 경우에도, 그 후에는 항상 입력 파일로 취급되는 =문자.


FILENAME으로 끝나는 명시 적 경로가 어떻게 문제인지 알 수 없습니다. 어느 awk 스크립트는 (를 포함하여 이에 국한되지 FILENAME에서 끝나는 경로의 모든 종류의 처리해야하는 경우, 일반적이며 ../foo, /path/to/foo경우에하는 - 다른 인코딩에있는 경로) substr(FILENAME,3)충분하지 않을 것이다, 또는 그것의 사용자가 기본적으로 파일 이름이 무엇인지 알고있는 원샷 스크립트 –이 경우 아마도 =;-)를 포함하는 파일을 신경 쓰지 않아야 합니다.
mosvy

2
@mosvy 나는 그것이 ./문제 라고 너무 많이 말하지는 않지만 파일 이름이 출력에 포함 ./되어야 하는 경우와 같이 특정 조건에서는 바람직 하지 않을 수 있다고 생각합니다 .이 경우 중복되고 불필요해야합니다. 어떻게 든 그것을 제거해야합니다. 최소한 하나의 예가 있습니다. 사용자는 파일 이름이 무엇인지 알고 있습니다.이 경우 파일 이름이 무엇인지 알지만 =여전히 적절한 처리를 방해합니다. 따라서지도가 -방해받을 수 있습니다 .
Sergiy Kolodyazhnyy

@mosvy, 그렇습니다.이 기능 은 ./접두사 를 사용하여 해당 awk기능 을 해결하고 싶지만 ./출력에서 출력을 제거하려고합니다. 파일의 첫 줄에 특정 문자열이 포함되어 있는지 확인하는 방법을 참조하십시오 . 예로서.
Stéphane Chazelas

로컬 (이 디렉토리에 상대적) 일뿐만 아니라 awk가 인수를 파일로 해석하게 ./하는 전역 (절대 경로)이기도 /합니다.
이삭

21

대부분의 awk 버전에서 프로그램이 실행 한 후의 인수는 다음 중 하나입니다.

  1. 파일
  2. 양식의 할당 x=y

파일 이름이 사례 # 2로 해석되고 있기 때문에 awk는 stdin에서 읽을 내용을 계속 기다리고 있습니다 (파일 이름이 전달 된 것으로 인식하지 못하기 때문에).

이 동작은 POSIX에 문서화되어 있습니다 .

다음 두 가지 유형의 인수를 혼합 할 수 있습니다.

  • file : 읽을 입력이 포함 된 파일의 경로 이름으로, 프로그램의 패턴 세트와 일치합니다. 파일 피연산자가 지정되지 않았거나 파일 피연산자가 '-'인 경우 표준 입력이 사용됩니다.
  • 할당 : 휴대용 문자 집합에서 밑줄 또는 영문자로 시작하는 피연산자 (IEEE Std 1003.1-2001의 기본 정의 볼륨, 6.1, 휴대용 문자 집합의 표 참조) 뒤에 밑줄, 숫자, 휴대용 문자 집합의 알파벳 문자와 '='문자는 경로 이름 대신 변수 할당을 지정해야합니다.

따라서, 몇 가지 옵션이 있습니다 (# 1은 가장 방해가되지 않습니다).

  1. "이동식 문자 세트의 밑줄 또는 알파벳 문자"가 아니기 awk ... ./my=file때문에이를 회피하는을 사용하십시오 ..
  2. 를 사용하여 파일을 stdin에 놓으십시오 awk ... < my=file. 그러나 이것은 여러 파일에서 제대로 작동하지 않습니다.
  3. 파일에 일시적으로 하드 링크를 만들고 사용하십시오. 과 같은 작업을 수행 ln my=file my_file한 다음 my_file정상적으로 사용할 수 있습니다 . 복사가 수행되지 않으며 두 파일 모두 동일한 데이터와 inode 메타 데이터로 백업됩니다. 사용 후에는 inode에 대한 참조 수가 여전히 0보다 커서 생성 된 링크를 제거하는 것이 안전합니다.

6
./my=file 작동 하지 않습니까? 유효한 변수 이름이 아니기 % awk 'processing_script_here' ./my=file.txt awk: fatal: cannot open file ./my=file.txt' for reading (No such file or directory). 때문에 이식성이 뛰어나므로 ./my그렇게 해석해서는 안됩니다.
Stephen Harris

2
POSIX 텍스트에서 알 수 있듯이 문제는 첫 번째 문자= 앞에 휴대용 문자 세트의 밑줄 또는 알파벳 문자가 오는 경우에만 발생합니다 (IEEE Std 1003.1-2001의 기본 정의 볼륨, 6.1, 휴대용 문자 세트의 표 참조). 휴대용 문자 집합에서 밑줄, 숫자 및 알파벳 순서가 이어집니다 . 그래서 파일과 같은 경로 ++foo=bar.txt=foo또는 ./foo=bar그 모든 OK입니다 .또는 +하지 않은 것입니다 [_a-zA-Z].
Stéphane Chazelas

1
@SergiyKolodyazhnyy awk는 셸 외부에 있으므로 어떤 것을 사용하든 상관 없습니다. ./my=file그대로 전달됩니다.
Chris Down

1
@SergiyKolodyazhnyy와 동일합니다 awk '{print $1,$2}' /etc/passwd. 요점은 awk와 달리 셸에서 파일을 여는 것이 파일을 찾을 수 있는지 여부와는 아무런 차이가 없다는 것입니다. 실제로에서에서 첫 번째 레코드의 끝까지 되돌아 가서 stdin 내의 위치를 ​​벗어나지 않도록 awk '{exit}' < /etc/passwd기대할 awkexit있습니다. POSIX가 필요합니다. /usr/xpg4/bin/awk솔라리스에서는 이 작업을 수행하지만 GNU / Linux에서는 그렇게 하지 gawk않습니다 mawk.
Stéphane Chazelas

3
@mosvy, 입력 파일 참조 에서 섹션 pubs.opengroup.org/onlinepubs/9699919799/utilities/...을 그것은 단지 당신이 그것을에 파일 또는 쓰기 데이터를 절단 할 때와 같은 일반 파일과 이해가 사용 패턴의 숫자에 유용 awk그런 식으로 식별 된 위치 .
Stéphane Chazelas

3

gawk 문서 를 인용하려면 (참고 강조 사항 추가) :

명령 행의 추가 인수는 일반적으로 지정된 순서대로 처리 할 입력 파일로 처리됩니다. 그러나 var = value 형식의 인수는 값을 변수 var에 지정합니다. 파일을 전혀 지정하지 않습니다.

왜 명령이 멈추고 기다 립니까? 양식 에 위의 정의에 의해 awk 'processing_script_here' my=file.txt 지정된 파일이 없기my=file.txt 때문에 변수 할당으로 해석되며, 정의 된 파일이 없으면 awkstdin을 읽을 것입니다 (이 strace명령의 awk가 read(0,'...)syscall을 기다리고 있음을 나타냅니다) .

이것도 POSIX awk 사양에 문서화되어 있습니다. OPERANDS 섹션과 그 할당 부분을 참조하십시오 )

변수 할당은 / etc / passwd의 모든 행에 대해 awk '{print foo}' foo=bar /etc/passwdfoo이 인쇄 된다는 점 에서 분명 합니다. ./foo=bar그러나 지정 하거나 전체 경로가 작동합니다.

참고 실행 straceawk '1' foo=bar뿐만 아니라 함께 확인 cat foo=bar이 AWK-특정 문제이며, 인수가 전달로 포탄이 경우 ENV 변수 할당과는 아무 상관이없는, 그래서는 execve는, 쇼 파일 이름을한다는 것을 보여줍니다.

또한 awk '...script...' foo=bar환경 변수 지정이 명령보다 먼저 적용되어야하므로 쉘에 의한 환경 변수 작성이 발생하지 않습니다. 만나다POSIX Shell Grammar Rules , 포인트 번호 7을 . 또한이를 통해 확인할 수 있습니다awk '{print ENVIRON["foo"]}' foo=bar /etc/passwd

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.