exec
플래그 사용 방법을 읽고 있습니다 -a
. 이것SS64 문서정확한 것 같습니다.
구현하다:
주문 실행
통사론:
exec [-cl] [-a name] [command [arguments]]
옵션:
-c Causes command to be executed with an empty environment. -l Place a dash at the beginning of the zeroth arg passed to command. (This is what the login program does.) -a The shell passes name as the zeroth argument to command.
이를 테스트하기 위해 두 개의 스크립트를 작성했습니다. 하나는 name foo/baz
이고 다른 하나는 다음과 같습니다 foo/buzz
.
#!/usr/bin/env bash
# foo/baz
exec -a blah ./foo/bar 1 2
#!/usr/bin/env bash
# foo/buzz
exec ./foo/bar 1 2
이러한 각 스크립트는 foo/bar
다음을 수행하는 동일한 아래 첨자를 실행합니다.
#!/usr/bin/env bash
echo "Hello world"
echo "0: $0"
echo "1: $1"
echo "2: $2"
-a
내 목표는 0번째 및 후속 매개변수에 어떤 영향이 미치는지 확인하는 것입니다 . -a
0번째 매개변수가 플래그에 전달한 매개변수로 변경 되면 -a
실행할 때 0번째 매개변수가 foo/baz
될 것으로 예상합니다. blah
왜냐하면 그것이 내가 전달한 것이기 때문입니다 -a
. 그러나 스크립트를 실행하면 두 경우의 출력은 동일합니다.
~/Workspace/OpenSource (master) $ ./foo/baz
Hello world
0: /Users/richiethomas/Workspace/OpenSource/foo/bar
1: 1
2: 2
~/Workspace/OpenSource (master) $ ./foo/buzz
Hello world
0: /Users/richiethomas/Workspace/OpenSource/foo/bar
1: 1
2: 2
내가 뭐 잘못 했어요? 아니면 내 기대가 뭔가 잘못된 걸까?
또한 관련 질문입니다. $1, $2, $3 등을 통해 들어오는 매개변수에 액세스하는 대신 0번째 매개변수를 재정의하는 사용 사례는 무엇입니까?
답변1
0번째 매개변수를 재정의하는 사용 사례는 무엇입니까...?
일부 프로그램은 호출 방법에 따라 동작을 변경합니다. 예를 들어,busybox
이런 식으로 동작하는 다중 호출 바이너리입니다. exec -a
0번째 매개변수의 값에 따라 다른 동작이 나타납니다.
$ bash -c 'exec -a date /usr/sbin/busybox'
Sat Sep 17 20:22:14 EDT 2022
$ bash -c 'exec -a uptime /usr/sbin/busybox'
20:22:17 up 23:48, load average: 0.10, 0.20, 0.15
이는 또한 exec -a <something>
문서화된 대로 작동함을 보여줍니다.
내가 뭐 잘못 했어요? 아니면 내 기대가 뭔가 잘못된 걸까?
여기서 문제는 쉘 스크립트를 사용하고 있다는 것입니다. ./foo/baz
명령줄에 입력할 때 실제로는 라는 명령을 실행하는 것이 아닙니다 ./foo/baz
. 와 같은 명령을 실행하는 것입니다 /bin/bash /path/to/foo/baz
. 셸에 전달된 0번째 인수에 영향을 주기는 하지만 ... 셸은 신경 쓰지 않고 다음을 포함 exec -a
하여 셸 스크립트에 표시되는 변수를 설정할 때 자체 논리를 사용합니다.$0
스크립트name) 및 위치 매개변수 $1
, $2
... (스크립트의 매개변수 포함).
(이것은 쉘 스크립트에만 국한된 것이 아닙니다. 거의 모든 해석된 코드에 동일하게 적용됩니다.)
답변2
이는 기본 바이너리가 아닌 해석된 스크립트를 호출하기 때문입니다. 이 C 프로그램을 컴파일하고 ./foo/bar
스크립트가 원래 있었던 위치에 결과를 배치합니다 .
#include <stdio.h>
int main(int argc, char **argv) {
puts("Hello world");
for(int i = 0; i < argc; ++i)
printf("%d: %s\n", i, argv[i]);
}
이렇게 하면 예상한 동작이 표시됩니다. 차이점이 있는 이유는 해석된 스크립트가 호출될 때 argv[0]
인터프리터에게 스크립트의 이름을 알려주기 위해 하이재킹된다는 점입니다. 대부분의 경우 어쨌든 그렇기 때문에 일반적으로 이것은 눈에 띄지 않습니다. 당신은 그것을 다르게 만들기 위해 노력하기 때문에 그것을 알아 차립니다.
답변3
중요한 점은 이것이 명령줄의 명령에 대해 exec
고유하게 설정 된다는 것입니다.$0
예를 들면 다음과 같습니다.
$ bash
$ exec -a SomeName sh -c 'echo "The name is: $0"'
The name is: SomeName
우연히도 exec가 쉘을 대체하기 때문에 쉘이 닫히고, exec가 끝나면 쉘 프로세스도 마찬가지입니다. 그렇기 때문에 명령을 사용하여 새 쉘을 요청해야 합니다 bash
. 그렇지 않으면 쉘이 닫히고 터미널도 닫힙니다.
exec 명령의 기능을 따르려면 다음을 시도하십시오.
$ strace -fe execve bash -c 'exec -a SomeName echo test' one two
execve("/usr/bin/bash", ["bash", "-c", "exec -a SomeName echo test", "one", "two"], 0x7ffdca326e60 /* 77 vars */) = 0
execve("/usr/bin/echo", ["SomeName", "test"], 0x55d4dcf02c50 /* 76 vars */) = 0
test
+++ exited with 0 +++
이는 호출 이름이 변경될 때 일부 실행 파일을 변경하는 데 유용합니다.
$ ( exec -a date -- busybox -ud '12:34' +'%F %T %Z' )
2022-09-18 12:34:00 UTC
$ ( exec -a ls busybox )
fileone
filetwo