shebang (예 : #!)과 함께 awk에 여러 인수를 사용하는 방법은 무엇입니까?


118

shebang 을 사용하여 gawk 스크립트 를 실행하고 싶습니다 --re-interval. "순진한"접근 방식

#!/usr/bin/gawk --re-interval -f
... awk script goes here

gawk가 첫 번째 인수 "--re-interval -f"(공백 주위로 분할되지 않음 )로 호출 되었기 때문에 작동 하지 않습니다. 이에 대한 해결 방법이 있습니까?

물론 gawk를 직접 호출 할 수는 없지만 첫 번째 인수를 분할하는 쉘 스크립트로 래핑하거나 gawk를 호출하고 스크립트를 다른 파일에 넣는 쉘 스크립트를 만들 수 있지만, 할 방법이 있는지 궁금합니다. 이것은 하나의 파일 내에 있습니다.

shebang 라인의 동작은 시스템마다 다릅니다. 적어도 Cygwin 에서는 인수를 공백으로 분할하지 않습니다. 나는 그저 그렇게 동작하는 시스템에서 그것을 어떻게하는지에 관심이 있습니다. 스크립트는 이식 할 수 없습니다.


1
내가 방금 한 어리석은 실험은 shebang 라인에서 다른 스크립트를 사용하는 한 스크립트로 인수를 올바르게 분할했습니다.
Hasturkun

@Hasturkun은 호출 된 프로그램 자체가 스크립트가 될 수 있는지 여부에 따라 shebang 라인의 동작이 시스템마다 다르다는 또 다른 문제를 제기합니다.
dubiousjim 2012


최신 버전의 gawk (> = 4.0)에서는 --re-interval더 이상 필요하지 않습니다 ([ gnu.org/software/gawk/manual/… 참조 ).

답변:


25

이것은 (g) awk와 함께 작동하는 것 같습니다.

#!/bin/sh
arbitrary_long_name==0 "exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "$@"


# The real awk program starts here
{ print $0 }

#!실행에 유의하십시오. 따라서이 /bin/sh스크립트는 먼저 쉘 스크립트로 해석됩니다.

처음에는 간단히 시도 "exec" "/usr/bin/gawk" "--re-interval" "-f" "$0" "$@"했지만 awk는이를 명령으로 처리하고 모든 입력 행을 무조건 인쇄했습니다. 그것이 내가 넣은 이유 arbitrary_long_name==0입니다. 항상 실패해야합니다. 횡설수설 문자열로 바꿀 수 있습니다. 기본적으로, 쉘 스크립트에 악영향을 미치지 않는 awk의 잘못된 조건을 찾고있었습니다.

쉘 스크립트에서 arbitrary_long_name==0변수가 호출을 정의 arbitrary_long_name하고 세트가 같음 =0.


이것이 내 대답이지만 충분히 휴대 가능하고 견고 할 수 있는지 궁금합니다. 구체적으로에 의존합니까 bash, 아니면 POSIX와 함께 작동 sh합니까? 그리고 나는 awk자주 사용하지 않기 때문에 두 번째 줄의 트릭 awk이 줄을 무시 하는 좋은 방법인지 확신하지 못합니다 .
아론 McDaid

내가 궁금했던 것, +1, 그러나 아마도 바람직하지 않을 것입니다 (따라서 상대적인 투표).
Aaron Hall

@AaronHall이 어떤 문제를 가질 수 있는지 설명해 주시겠습니까? 변수 arbitrary_long_name가 실제 awk 프로그램에서 사용되는 변수와 충돌하지 않는 한 어떤 문제도 볼 수 없습니다. 내가 놓친 것이 있습니까?
아론 McDaid

#!/bin/sh -대신 사용 하여 첫 번째 문자 #!/bin/sh가있는 0 -번째 인수와 함께 호출되는 경우 스크립트가 위험한 방식으로 오작동하지 않도록 보호합니다 . 이것은 C와 같은 프로그래밍 언어에서 우연히 발생할 수 있습니다. 호출 된 프로그램 이름을 인수 배열의 일부로 execve및 유사한 함수 에 전달하는 것을 잊어 버림으로써 실수로 엉망이되기 쉽고 , 사람들이 습관적으로 보호하는 것을 잊는 경우에도 발생할 수 있습니다. 공격자가 대화 형 셸을 얻을 수 있도록하는 악의적으로 악용 가능한 취약점의 마지막 단계가됩니다.
mtraceur

161

shebang 라인은 POSIX, SUS, LSB 또는 기타 사양의 일부로 지정되지 않았습니다. AFAIK, 제대로 문서화되지도 않았습니다.

사이 모든 것을 가지고 : 그것은 무엇을하는지에 대한 대략적인 합의가 !\nexec그것. 가정은 사이의 모든 것 !하고는 \n인터프리터에 전체 절대 경로입니다. 공백을 포함하면 어떤 일이 발생하는지에 대한 합의가 없습니다.

  1. 일부 운영 체제는 단순히 전체를 경로로 취급합니다. 결국 대부분의 운영 체제에서 공백이나 대시는 경로에서 합법적입니다.
  2. 일부 운영 체제는 공백으로 분할되어 첫 번째 부분을 인터프리터의 경로로 취급하고 나머지는 개별 인수로 취급합니다.
  3. 일부 운영 체제는 첫 번째 공백 에서 분할되어 앞 부분을 interpeter의 경로로 취급하고 나머지 부분은 단일 인수로 취급합니다 (이는 여러분이보고있는 것입니다).
  4. 일부는 심지어 shebang 라인 을 전혀 지원하지 않습니다 .

고맙게도 1.과 4.는 사라진 것처럼 보이지만 3.은 꽤 널리 퍼져 있으므로 둘 이상의 인수를 전달할 수 있다는 것에 의존 할 수 없습니다.

명령의 위치도 POSIX 또는 SUS에 지정되지 않기 때문에, 당신은 일반적으로 실행 파일의 전달하여 하나의 인자 것을까지 사용할 이름env수 있도록 그것을 실행 파일의 위치를 확인할 수 있습니다; 예 :

#!/usr/bin/env gawk

[분명히 이것은 여전히에 대한 특정 경로를 가정 env하지만이 위치에있는 시스템이 거의 /bin없으므로 일반적으로 안전합니다. 의 위치는 또는 또는 같은 env위치보다 훨씬 더 표준화되어 있습니다 .]gawkpythonrubyspidermonkey

어떤 당신이 실제로 사용할 수 없음을 의미 있는 인수를 전혀 .


1
FreeBSD의 환경에는 -S여기에 도움 이되는 스위치가 있지만 내 Linux에는 존재 env하지 않으며 gygwin에서도 사용할 수 없다고 생각합니다. @hstoerr, 다른 상황의 다른 사용자가 나중에 질문을 읽을 수 있으므로 이식성이 필요하지 않더라도 일반적으로 이식 가능한 답변이 선호됩니다.
dubiousjim 2015

4
따라서 우리는 shebang에서 인수를 이식 가능하게 사용할 수 없습니다. 하지만 어떤 방법 으로든 논쟁이 필요하다면 어떻게해야합니까? 해결책은 #!/bin/sh및을 포함하는 래퍼 셸 스크립트를 작성하는 것 /usr/bin/env gawk --re-interval -f my-script.awk입니다. 그 맞습니까?
Rory O'Kane 2012-07-05

1
난 동의하지 않는다. 하나의 인수를 이식 가능하게 사용할 수 있습니다. 어떤 인수도 사용할 수없는 시스템은이 전통적인 유닉스주의를 구현하는 데 비참하게 실패합니다. 이것이 바로 해시 뱅입니다. 비 구현이 공정한 게임이라면 우리는 그 #!자체가 이식성이 없다고 안전하게 말할 수 있습니다 . 예를 들어 Windows는이 규칙을 "기본적으로"전혀 인식하지 못합니다. 유닉스에서 전통적으로 #!/usr/bin/awk -f.
Kaz

7
@Kaz : 예,하지만 많은 바이너리의 경로가 표준화되지 않았기 때문에 하나의 인수를 사용합니다 #!/usr/bin/env ruby.
Jörg W Mittag 2014-06-09

3
@Pacerier : POSIX 사양을 변경하고 모든 시스템이 사양을 준수하도록 업데이트 될 때까지 20 ~ 30 년을 기다리십시오.
Jörg W Mittag

18

정확하게 이식 할 수는 없지만 coreutils 8.30부터 설명서에 따라 다음을 사용할 수 있습니다.

#!/usr/bin/env -S command arg1 arg2 ...

그래서 주어진 :

$ cat test.sh
#!/usr/bin/env -S showargs here 'is another' long arg -e "this and that " too

당신은 얻을 것이다 :

% ./test.sh 
$0 is '/usr/local/bin/showargs'
$1 is 'here'
$2 is 'is another'
$3 is 'long'
$4 is 'arg'
$5 is '-e'
$6 is 'this and that '
$7 is 'too'
$8 is './test.sh'

그리고 당신이 궁금한 경우 showargs:

#!/usr/bin/env sh
echo "\$0 is '$0'"

i=1
for arg in "$@"; do
    echo "\$$i is '$arg'"
    i=$((i+1))
done

여기에 원래 답변 .


1
참고로 FreeBSD는 6.0 이후로 수년간 -S를 사용했습니다. 이것은 coreutils에 대한 환영받은 이식성 추가입니다.
Juan

12

나는 공백이 shebang에서 처리되는 방식 (적어도 Linux에서) 때문에 명백한 해결책이없는 동일한 문제를 발견했습니다.

그러나 짧은 옵션 이고 연결될 수있는 한 (GNU 방식) shebang에서 여러 옵션을 전달할 수 있습니다 .

예를 들어, 당신은 가질 수 없습니다

#!/usr/bin/foo -i -f

하지만 당신은 가질 수 있습니다

#!/usr/bin/foo -if

분명히 그것은 옵션에 짧은 등가물이 있고 인수가 없을 때만 작동합니다.


11

Cygwin과 Linux에서는 shebang 경로 이후의 모든 것이 하나의 인수로 프로그램에 구문 분석됩니다.

awkshebang 내부에 다른 스크립트 를 사용하여이 문제를 해킹 할 수 있습니다 .

#!/usr/bin/gawk {system("/usr/bin/gawk --re-interval -f " FILENAME); exit}

이것은 {system("/usr/bin/gawk --re-interval -f " FILENAME); exit}awk에서 실행 됩니다.
그리고 이것은 /usr/bin/gawk --re-interval -f path/to/your/script.awk시스템 쉘에서 실행 됩니다.


2
이 실 거예요 작품은 youve를 스크립트에 인수를 전달하는 경우
스티븐 페니

4
#!/bin/sh
''':'
exec YourProg -some_options "$0" "$@"
'''

위의 쉘 shebang 트릭은 /usr/bin/env.


'' ':'는 원래 솔루션이 python 스크립트를위한 것이기 때문에 '' ':'는 exec 부분을 무시하도록 python 인터프리터에게 알려줍니다.
user3123730

4
귀하의 솔루션이에 대한 것이기 때문에 귀하가 반대 투표를 받고 있다고 생각 python하지만이 질문은에 관한 것 awk입니다.
아론 McDaid

1
파이썬을위한 훌륭한 해킹.
Zaar Hai

3

gawk 매뉴얼 (http://www.gnu.org/manual/gawk/gawk.html)에서 섹션 1.14의 끝 부분에서는 shebang 라인에서 gawk를 실행할 때 단일 인수 만 사용해야한다는 점에 유의하십시오. OS는 gawk 경로 이후의 모든 것을 단일 인수로 취급한다고 말합니다. --re-interval옵션 을 지정하는 다른 방법이 있습니까? 아마도 스크립트는 shebang 줄에서 쉘을 참조 gawk하고 명령으로 실행 하고 스크립트 텍스트를 "here document"로 포함 할 수 있습니다.


옵션을 지정하는 다른 방법이없는 것 같습니다. 당신 말이 맞습니다 : gawk -f-<< EOF, 몇 줄의 스크립트, EOF는 작동하지만 그것은 내가 gawk로 표준 입력을 읽지 못하게합니다.
Hans-Peter Störr 2010

여기 문서는에 대한 표준 입력 스트림을 차지 gawk하지만 stderr를 통해 무언가를 파이프 할 수 있습니다 (즉,이 스크립트에 파이핑하기 전에 stdout을 stderr로 리디렉션). 나는 실제로 그것을 시도한 적이 없지만 첫 번째 프로세스가 stderr에서 아무것도 방출하지 않는 한 작동 할 수 있습니다. 다른 어떤 것도 사용하고 있지 않은지 확인하려면 명명 된 파이프 ( linuxjournal.com/content/using-named-pipes-fifos-bash )를 만들 수도 있습니다.
bta 2010

3

bashand gawk자체를 사용 하여 shebang을 건너 뛰고 스크립트를 읽고 파일로의 두 번째 인스턴스에 전달하는 것은 gawk [--with-whatever-number-of-params-you-need]어떻습니까?

#!/bin/bash
gawk --re-interval -f <(gawk 'NR>3' $0 )
exit
{
  print "Program body goes here"
  print $1
}

(-예를 들어 자연적으로도 동일한 결과를 얻을 수 있습니다. sedtail,하지만 난에만 따라 아름다움의 일종 있다고 생각 bash하고 gawk자체)


0

재미를 위해 : 파일 설명자 3과 4를 통해 stdin과 프로그램을 다시 라우팅하는 다음과 같은 매우 이상한 솔루션이 있습니다. 스크립트에 대한 임시 파일을 만들 수도 있습니다.

#!/bin/bash
exec 3>&0
exec <<-EOF 4>&0
BEGIN {print "HALLO"}
{print \$1}
EOF
gawk --re-interval -f <(cat 0>&4) 0>&3

한 가지 성가신 점은 쉘이 스크립트에서 변수 확장을 수행하므로 모든 $ (스크립트의 두 번째 줄에서 수행됨)를 인용해야하며 그 이상일 것입니다.


-1

휴대용 솔루션의 경우 awk대신 사용 하고 shebang으로 gawk표준 BOURNE 셸 ( /bin/sh)을 호출하고 awk직접 호출 하여 명령 줄에서 프로그램을 stdin을 통하지 않고 here 문서로 전달합니다.

#!/bin/sh
gawk --re-interval <<<EOF
PROGRAM HERE
EOF

참고 :-f에 인수를 awk. 떠나는 stdin사용할 수는 awk입력에서 읽을 수 있습니다. 당신이 당신의 원래 예제로하려고했던 모든 것을 달성 했다고 가정 gawk하고 PATH, 당신이 원래 예제로하려고했던 모든 것을 달성했다고 가정합니다 (파일 내용이 입력이 아닌 awk 스크립트가되기를 원한다고 가정하면 shebang 접근 방식이 그것을 다음과 같이 취급했을 것이라고 생각합니다. ).


3
그것은 나를 위해 작동하지 않았습니다. bash man은 <<< blabla가 blabla를 stdin에 넣습니다. <<-EOF를 의미 했습니까? 어느 쪽이든, 그것은 또한 프로그램을 stdin에 넣습니다.
Hans-Peter Störr 2013 년
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.