AWK가 호출되고 ^C != 0으로 중단되면 bash가 종료됩니다.

AWK가 호출되고 ^C != 0으로 중단되면 bash가 종료됩니다.

다음 (G)AWK 스크립트 조각에 대한 질문이 있습니다.

do {
    ...
} while (system("sleep 10"))

내 의도는 사용자가 절전 모드 중에 ^C를 누를 때 루프를 끊는 것이지만 작동하지 않습니다.

문제는 적어도 AWK에 의해 실행될 때 ^C로 중단될 때 Bash가 0으로 종료된다는 것입니다 system().

$ awk 'BEGIN { print "\n" system("sleep 2") }'
(let the sleep complete)
0

 

$ awk 'BEGIN { print "\n" system("sleep 2") }'
^C
0

왜 그럴까요?

이것은 Bash 또는 (G)AWK의 버그입니까?

예를 들어 복잡한 Bash 특정 구문을 포함하지 않는 간단한 솔루션이 있습니까 trap?

내가 생각할 수 있는 최선은 다음과 같습니다.

do {
    ...
} while (42 == system("sleep 10 && exit 42"))

나에게 그것은 여전히 ​​​​잘못된 자갈처럼 느껴집니다.

답변1

system()무엇을 반환해야합니까 ?모호하게 지정됨.

구현에서 공통적으로 보이는 것은 awk정상적인 종료 시 종료 코드(모듈로 256 으로 전달된 숫자 exit(3))를 반환하지만 쉘 프로세스가 신호에 의해 종료될 때 동작이 많이 다르다는 것입니다.

또한 C 함수는 상위 항목에서 SIGINT(및 SIGQUIT)를 무시하도록 설계되었지만 해당 요구 사항이 s system(3)에도 적용되는지 여부는 (적어도 나에게는) 명확하지 않습니다 . 일부 구현(예: )은 해당 SIGINT에서 종료됩니다(함수 를 실행 중이라는 이유만으로 CTRL-C를 무시 하는 것을 좋아하지 않기 때문에 보고 싶은 동작이기도 함 ). 일부(예: 또는 레거시 구현) ) 에 있을 것입니다.awksystem()awkmawkawksystem()gawk

또한 일부 쉘은 이러한 신호 중 일부를 가로채서 결국 호출할 수 있으며 exit()이는 동작에 영향을 미칠 수 있습니다(예: Bourne 쉘에 대한 설명의 설명 참조). 이는 exec아래 예에서 쉘을 제거하기 위해 사용하는 것입니다. 루프 이유.

SIGINT에 반환된 값( 1을system() 고려하면 더 많은 변형 )에 대해 다음을 볼 수 있습니다.close()

$ nawk 'BEGIN {print system("exec kill -s INT $$")}'
0.0078125
$ bwk-awk 'BEGIN {print system("exec kill -s INT $$")}'
0.0078125
$ mawk 'BEGIN {print system("exec kill -s INT $$")}'
130
$ gawk 'BEGIN {print system("exec kill -s INT $$")}'
0

0.00781252 / 256( 코어가 덤프된 경우 0.542969((128+11)/256) SEGV, 그렇지 않은 경우 0.0429688(11/256)), 11Solaris 10 또는 11 또는 Linux 포트의 Heirloom Toolbox에서 nawk찾을 수 있음 nawk, bwk-awkawkBrian Kernighan이 직접 관리함( K가운데 awk) 일부 BSD에서 찾을 수 있는 기본 사항 awk(Debian GNU/Linux에서 테스트했습니다). /usr/xpg4/bin/awkSolaris 11에서 동작은 gawk.

따라서 s반환된 값 system(3)(비트 0~6은 신호 번호, 비트 7은 코어 비트, 비트 8~15는 종료 코드인 정수)을 기반으로 위의 결과는 다음과 같이 awk반환됩니다 system().

  • s / 256(전통적인 awk구현),
  • int(s/256)( gawk),
  • 또는 mawkBourne 또는 C 쉘과 같은 쉘이 수행하는 것과 동일한 변환( (s&127)+128종료된 경우, s>>8그렇지 않은 경우)을 제외하고 코어가 덤프된 경우 (s&127)+256대신 (s&127)+128(의 값 (s&255)+128)을 얻습니다.

여기서는 다음과 같이 할 수 있습니다.

awk 'BEGIN{print system("trap exit\\ 1 INT; sleep 10")}'

그러나 여전히 일부 구현이 awk종료될 수 있습니다. 귀하의 것이 또는인 경우 다음을 수행할 수 있습니다.awkmawkshbashyash

awk 'BEGIN{print system("set -m; sleep 10; exit")}'

따라서 sleep자체 프로세스 그룹에서 실행됩니다(그리고 SIGINT만 얻습니다).

또 다른 옵션은 호출하기 전에 SIGINT를 무시하는 것입니다 awk. 그러나 대부분의 쉘(POSIX 요구 사항)은 시작 시 신호가 무시된 경우 신호 처리기를 변경할 수 없습니다. 그래서 다음과 같습니다.

(
  trap '' INT
  awk 'BEGIN{print system("trap exit\\ 1 INT; sleep 10; exit")}'
)

작동하지 않습니다. zsh그러나 그러한 (자기 발생) 제한은 없으므로 zsh사용 가능하다는 것을 알고 있는 경우 다음을 수행할 수 있습니다.

(
  trap '' INT
  awk 'BEGIN{print system("exec zsh -c \"TRAPINT() exit 1; sleep 10\"")}'
)

awk둘 중 하나가 mawk작동 gawk하고 작업 제어를 방해하지 않을 수 있습니다. 하지만 이 시점에서는 필요에 따라 신호 처리를 조정할 수 있는 perl// python... ruby대신 사용을 고려해 볼 가치가 있습니다 .awk

노트

1close() 파이프 위:

awk 'BEGIN {cmd = "kill -s INT $$"; cmd | getline; print close(cmd)}'

첫째, 이것은 내가 시도한 모든 구현에서 ^C중단됩니다 ( SIGINT/SIGQUIT가 awkfor를 무시하거나 좋아하는 요구 사항 은 없습니다 (이를 구현하는 자연스러운 방법 ) ).popen(3)pclose(3)getlinesystem(3)

s그러나 종료 상태(위와 같은/ 반환된 값이 있는 위치) 에 관해서는 다음 을 볼 수 있습니다.pclose(3)waitpid(2)system()

  • Solaris nawk: 작동하지 않습니다. close()Solaris에서는 그렇게 부를 수 없습니다 nawk.
  • /usr/xpg4/bin/awk솔라리스에서. exit(1)프로세스가 완료 되더라도 항상 0을 반환합니다. 분명히 일관성 오류입니다.
  • gawkbwk-awk: 제공 s( exit 1256 제공, SIGINT로 킬 2 제공, SIGSEGV 11로 킬, 코어 제공 139).
  • mawk: 와 동일하며 이를 고려한 유일한 구현인 것 같습니다 system().mawk

관련 정보