mawk에서 자체 스크립트 이름을 인쇄하는 방법은 무엇입니까?


13

bash $0에는 스크립트 이름이 포함되어 있지만 다음 내용으로 myscript.awk라는 스크립트를 만들면 awk에 있습니다.

#!/usr/bin/awk -f
BEGIN{ print ARGV[0] }

실행하면 "awk"만 인쇄됩니다. 또한 i> 0 인 ARGV [i]는 명령 행의 스크립트 인수에만 사용됩니다. 그렇다면 스크립트 이름 (이 경우 "myscript.awk")을 인쇄하는 방법은 무엇입니까?


모든 솔루션에는 gawk가 필요하고 일반적인 awk, 특히 널리 사용되는 mawk (예 : Ubuntu의 기본값)에서 작동하지 않기 때문에 제목을 awk에서 mawk로 변경했습니다.
cipper

mawk우분투에서 기본값 이라고 생각하는 것은 무엇입니까 ? 내 15.04 VM에서 기본값 awkgawk입니다. mawk가 설치되어 있지만 기본값은 아닙니다.
terdon

1
로 전화하면 awk 스크립트 awk -f myscript.awk입니다. 그러나 이것은 문제의 문제와 관련이 없습니다.
cipper

1
@EdMorton로 awk시작하기 때문에 스크립트입니다 #!/usr/bin/awk -f. 쉘 스크립트는 다른 것으로 시작합니다 #!/bin/sh.
Barmar

1
나는 다양한 쉘 전문가들과 이야기를 나 and으며 그것이 쉘인지 또는 awk 스크립트인지에 대한 확실한 대답을 얻으려고 노력했으며 POSIX에 따르면 #로 시작하는 파일의 해석에 놀랍게도! 정의되지 않았으며 특정 유형 이름이 없습니다. 어떤 사람들은 이것을 쉘이나 awk 스크립트가 아닌 "해시 뱅 인터프리터 스크립트"라고 부르지 만, awk가 여전히 있기 때문에 커널 (쉘이 아닌)이 첫 번째 라인을 해석하더라도 awk 스크립트로 간주되어야한다는 의견이 일치합니다. 첫 번째 줄도 (주석으로) 구문 분석 할 수 있어야하며를 사용하여 실행할 수 있습니다 awk -f file.
Ed Morton

답변:


5

cygwin의 bash에서 GNU awk 4.1.3으로 :

$ cat tst.sh
#!/bin/awk -f
BEGIN { print "Executing:", ENVIRON["_"] }

$ ./tst.sh
Executing: ./tst.sh

나는 그것이 얼마나 휴대용인지 모르겠다. 그러나 항상 그렇듯이 쉘 스크립트에서 shebang을 사용하여 awk 스크립트를 실행하지는 않습니다. 간단하게 유지하고 대신이 작업을 수행하십시오.

$ cat tst2.sh
awk -v cmd="$0" '
BEGIN { print "Executing:", cmd }
' "$@"

$ ./tst2.sh
Executing: ./tst2.sh

마지막으로 모든 플랫폼의 모든 쉘에서 현대적인 기능을 사용할 수 있습니다.


첫 번째는 bash, zsh 또는 ksh에서만 작동합니다. 후자는 awk 스크립트가 아닌 쉘 스크립트에 관한 것입니다.
cuonglm

2
감사합니다! ENVIRON["_"]완벽하게 작동하며 외부 프로그램을 호출하지 않습니다. 두 번째 옵션 awk -v ...은 스크립트 실행 방법에 따라 다릅니다. 나는 이것을 원하지 않습니다.
cipper

1
스크립트를 호출하는 tst.sh것은 잘못된 것입니다. 그것은의 awk스크립트가 아닌 쉘 스크립트. BEGIN유효한 쉘 명령이 아닙니다.
Barmar

1
맞지만 이식성 문제는 "ENVIRON [] 이식성"이 아니라 " ENVIRON["_"]모든 쉘에서 shebang을 통해 호출되는 모든 awk에서 인쇄 될 때 호출 쉘 스크립트 경로를 생성합니까?" 나는 개인적으로 대답에 관심이 없지만 언급 할 것이라고 생각하기 위해 shebang에서 awk 스크립트를 호출하지 않을 것입니다 .... 나는 위의 의견에서 @cuonglm이 일부 쉘에서만 지원된다고 대답했습니다. .
Ed Morton

1
좋은 지적, @Ed. 대시 실패 (현재 명령이 아닌 이전 명령 (또는 셸 자체) 를 반환 함 )로 확인되었습니다. ksh93은 흥미롭게도 PID 앞에 별표를 붙입니다 (예 :) *12345*/tmp/test.awk. ARGV[0]항상 awk대시, bash, zsh 및 ksh93입니다.
Adam Katz

5

나는 이것이 gawk 문서에 따라 가능하다고 생각하지 않습니다 .

마지막으로 ARGV[0](7.5 내장 변수 참조) 값은 운영 체제에 따라 다릅니다. 일부 시스템 awk에는 awk의 전체 경로 이름 (예 :)을 넣고 일부 시스템 에는 /bin/awk스크립트 이름 ( 'advice')을 넣습니다. ARGV[0]스크립트 이름을 제공 하는 가치에 의존하지 마십시오 .

linux당신은 더러운 해킹의 종류를 사용하여 시도 별 댓글에서 지적 할 수 스테판 Chazelas가 구현 경우이 가능합니다 awk지원은 NUL이 바이트 :

#!/usr/bin/awk -f

BEGIN { getline t < "/proc/self/cmdline"; split(t, a, "\0"); print a[3]; }

스크립트가 작동하지 않는 것 같습니다. "awk -f script.awk"로 호출하면 "k"를 인쇄하고 "./script.awk"로 호출하면 "s"를 인쇄합니다
cipper

@ cipper : 여기에서 작동 gawk하고 (설명처럼) 실패합니다 mawk. 흥미 롭습니다!

그것은 리눅스에서 작동합니다 awk-4.0.2. 와 FreeBSD의에서 /proc/curpoc/cmdline, 그리고 awk그 결과로 당신 만의 작품 같다 gawk.
taliezin

기본 우분투에서는 작동하지 않습니다. 휴대용 솔루션을 찾는 것이 좋습니다.
cipper

1
@taliezin : cuonglm의 대답은 스크립트 이름을 수동으로 공급해야하기 때문에 해결책이 아닙니다. awk -vNAME="myscript.awk" ./myscript.awk스크립트 내에서 NAME을 호출 한 다음 인쇄 하는 것과 같습니다 . 해결책이 아닙니다.
cipper

5

awk 내에서 명령 이름을 얻는 직접적인 방법을 모르겠습니다. 그러나 하위 쉘을 통해 찾을 수 있습니다.

둔한 사람

GNU awk 및 ps명령을 사용하면 프로세스 ID를 사용 PROCINFO["PID"]하여 명령 이름을 임시 해결책으로 검색 할 수 있습니다 . 예를 들면 다음과 같습니다.

cmdname.awk

#!/usr/bin/gawk -f

BEGIN {
  ("ps -p " PROCINFO["pid"] " -o comm=") | getline CMDNAME
  print CMDNAME
}

mawk and nawk

동일한 접근 방식을 사용할 수 있지만 특수 쉘 변수 (부모 awk의 PID)에서 PID를 파생시킵니다 $PPID.

cmdname.awk

#!/usr/bin/mawk -f

BEGIN { 
  ("ps -p $PPID -o comm=") | getline CMDNAME
  print CMDNAME
}

테스팅

다음과 같이 스크립트를 실행하십시오.

./cmdname.awk

두 경우 모두 출력 :

cmdname.awk

오류가 발생했습니다 : / bin / sh : 1 : -o : 찾을 수 없음
cipper

@ cipper : 이것은 GNU awk에서만 작동합니다. 누락 된 shebang 줄을 추가했습니다.
Thor

에서 둔한 설명서 : POSIX에 따르면, '표현 | 식에 '$'이외의 괄호로 묶지 않은 연산자가 포함 된 경우 getline '은 모호합니다 (예 :' "echo" "date"| 연결 연산자가 괄호로 묶이지 않기 때문에 getline '이 모호합니다. '( "echo" "date")로 작성해야합니다. | 프로그램을 모든 awk 구현에 이식 가능하게하려면 getline '.
cipper

1
가 필요한 경우 gawk그것은이다 gawk대신의 솔루션 awk솔루션. 나는 @cipper가 그의 소망 "휴대용 솔루션"을 질문에 추가해야한다고 생각합니다.

1
@Thor : cuonglm의 대답은 스크립트 이름을 사용하여 수동으로 피드해야하기 때문에 솔루션이 아닙니다. awk -vNAME="myscript.awk" ./myscript.awk스크립트 내에서 NAME을 호출 한 다음 인쇄 하는 것과 같습니다 . 해결책이 아닙니다.
cipper

4

POSIX로 awk:

#!/usr/bin/awk -f

BEGIN {
    print ENVIRON["AWKSCRIPT"]
}

그때:

AWKSCRIPT=test.awk ./test.awk
test.awk

4
당신은 수동으로 스크립트의 이름을 공급,이 자체 인쇄 방법이 아니다
cipper

@ cipper : 글쎄, 그것이 내가 상상할 수있는 가장 쉽고 휴대용 방법입니다.
cuonglm

2
스크립트 내에서 awk -vNAME="myscript.awk" ./myscript.awk변수를 호출 한 다음 인쇄하는 것과 같습니다 NAME. 해결책이 아닙니다.
cipper

@ cipper : 당신이 언급한다면 그것은 유일한 방법 mawk입니다. 또한를 사용 ENVIRON하는 것과 이스케이프 시퀀스가 -vNAME="myscript.awk"언제 mawk확장 되므로 를 사용하는 것과 동일하지 않습니다 NAME.
cuonglm

4

GNU awk 사용

점검 GNU의 AWK 사용 설명서를 - 7.5.2 내장 정보 전하는 그건 변수 내가 우연히 :

프로세스 번호

이 배열의 요소는 실행중인 awk 프로그램에 대한 정보에 대한 액세스를 제공합니다. 다음 요소 (알파벳순)는 사용 가능합니다.

PROCINFO [ "pid"]

현재 프로세스의 프로세스 ID

즉, 런타임 중에 프로그램의 PID를 알 수 있습니다. 그런 다음 system()주어진 PID로 프로세스를 찾는 데 사용 합니다.

#!/usr/bin/gawk -f
BEGIN{ pid=PROCINFO["pid"]
       system("ps -ef | awk '$2==" pid " {print $NF}'")
}

ps -ef두 번째 열에 PID를 표시하는을 사용 합니다. 실행이 완료 awk -f <script>되고 다른 매개 변수가 없다고 가정하면 행의 마지막 필드에 원하는 정보가 있다고 가정 할 수 있습니다.

매개 변수가있는 경우 줄을 다르게 구문 분석하거나 더 나은 방법으로 ps관심있는 열만 인쇄 하는 옵션을 사용해야 합니다.

테스트

$ awk -f a.awk 
a.awk
$ cp a.awk hello.awk
$ awk -f hello.awk 
hello.awk

GNU awk 사용자 안내서의 다른 장에서는 ARGV가 갈 길이 아니라고 말합니다 :

1.1.4 실행 가능한 awk 프로그램

마지막으로 ARGV [0]의 값 (내장 변수 참조)은 운영 체제에 따라 다릅니다. 일부 시스템에는 'awk'가 있고 일부 시스템에는 awk의 전체 경로 이름 (예 : / bin / awk)이 있고 일부 시스템에서는 스크립트 이름 ( 'advice')이 있습니다. (dc) 스크립트 이름을 제공하기 위해 ARGV [0]의 값에 의존하지 마십시오.


불행히도 PROCINFO는 일반적인 awk가 아닌 gawk 기능 일뿐입니다. 예를 들어 mawk (ubuntu에서 기본적으로 설치됨)에서 사용할 수 없습니다
cipper

알아요 ... 왜 [gawk]로 질문에 태그를 하셨나요?
fedorqui

네가 옳아. 질문을 게시했을 때 mawk와 gawk의 모든 차이점에 대해 알지 못했습니다. 태그가 이제 mawk로 변경되었습니다.
cipper

@cipper good :) 나는 실제로 테스트 mawk하고 있었고 그것을 작동시킬 수 없어서 gawk우분투에 설치 했고 효과가있었습니다. 따라서 해결책을 사용할 수 있습니다 gawk. D
fedorqui

1
@terdon gawk은 기본적으로 Ubuntu (또는 mawk기본 awk구현 인 일부 Ubuntu 버전)에 설치되지 않습니다 . IIRC, 데비안에서도 설치해야했습니다.
Stéphane Chazelas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.