다음 (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를 무시 하는 것을 좋아하지 않기 때문에 보고 싶은 동작이기도 함 ). 일부(예: 또는 레거시 구현) ) 에 있을 것입니다.awk
system()
awk
mawk
awk
system()
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.0078125
2 / 256
( 코어가 덤프된 경우 0.542969((128+11)/256) SEGV
, 그렇지 않은 경우 0.0429688(11/256)), 11
Solaris 10 또는 11 또는 Linux 포트의 Heirloom Toolbox에서 nawk
찾을 수 있음 nawk
, bwk-awk
예awk
Brian Kernighan이 직접 관리함( K
가운데 awk
) 일부 BSD에서 찾을 수 있는 기본 사항 awk
(Debian GNU/Linux에서 테스트했습니다). /usr/xpg4/bin/awk
Solaris 11에서 동작은 gawk
.
따라서 s
반환된 값 system(3)
(비트 0~6은 신호 번호, 비트 7은 코어 비트, 비트 8~15는 종료 코드인 정수)을 기반으로 위의 결과는 다음과 같이 awk
반환됩니다 system()
.
s / 256
(전통적인awk
구현),int(s/256)
(gawk
),- 또는
mawk
Bourne 또는 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
종료될 수 있습니다. 귀하의 것이 또는인 경우 다음을 수행할 수 있습니다.awk
mawk
sh
bash
yash
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가 awk
for를 무시하거나 좋아하는 요구 사항 은 없습니다 (이를 구현하는 자연스러운 방법 ) ).popen(3)
pclose(3)
getline
system(3)
s
그러나 종료 상태(위와 같은/ 반환된 값이 있는 위치) 에 관해서는 다음 을 볼 수 있습니다.pclose(3)
waitpid(2)
system()
- Solaris
nawk
: 작동하지 않습니다.close()
Solaris에서는 그렇게 부를 수 없습니다nawk
. /usr/xpg4/bin/awk
솔라리스에서.exit(1)
프로세스가 완료 되더라도 항상 0을 반환합니다. 분명히 일관성 오류입니다.gawk
및bwk-awk
: 제공s
(exit 1
256 제공, SIGINT로 킬 2 제공, SIGSEGV 11로 킬, 코어 제공 139).mawk
: 와 동일하며 이를 고려한 유일한 구현인 것 같습니다system()
.mawk