为什么一个 exec "sh -c a.out" 而不是 a.out 本身?
Why should one exec "sh -c a.out" instead of a.out itself?
我正在 https://opensource.apple.com/source/Libc/Libc-167/gen.subproj/popen.c.auto.html 研究 Apple 对 popen()
的实施,并注意到他们 execl(_PATH_BSHELL, "sh", "-c", command, NULL)
而不是 execl(_PATH_BSHELL, command, NULL)
。
为什么你想要(或者你应该)执行一个可执行文件,例如a.out
通过 sh -c
而不仅仅是可执行文件本身?
如果您执行 sh -c a.out
而不是 a.out
本身,实际的 a.out
进程是否最终成为“孙子”进程而不是 子进程进程?
Why would you want to (or should you) exec an executable, e.g. a.out
via sh -c
instead of just the executable itself?
popen()
设计用于 运行 shell 命令,包括 shell 语法,如 >
重定向、|
管道和 &&
命令链。它需要通过 sh -c
传递字符串以支持这些构造。如果没有,这些语法特征将作为参数逐字传递给相关程序。
例如,popen("make clean && make")
应该触发两次 make
调用。没有 sh -c
它会用三个参数调用 make
一次,就好像一个人输入了
$ make clean '&&' make
在航站楼。
If you exec sh -c a.out
instead of just a.out
itself, does the actual a.out
process end up being a "grandchild" process and not a child process?
是的,没错。在当前进程和a.out
之间会有一个sh
进程。
that they do execl(_PATH_BSHELL, "sh", "-c", command, NULL)
instead of execl(_PATH_BSHELL, command, NULL)
后者不会直接执行 command
,但是 _PATH_BSHELL
(/bin/sh
) 的 [=15=]
设置为 command
和 没有参数,导致 shell 期待来自其标准输入的命令。
此外,该语法依赖于 NULL
被定义为显式指针(例如 ((void*)0)
),而不仅仅是 0
,这在任何地方都无法保证。虽然他们可以在他们的实现中做到这一点(因为他们控制所有 headers),但这不是您应该在应用程序代码中做的。
不,execl(command, command, (void*)NULL)
也不会直接执行 command
,除非 command
是 a) 一个完整路径并且 b) 可执行格式(二进制或以 she-bang #!
开头的脚本——后者是 non-standard 扩展)。如果 command
是要在 PATH
中查找的简单命令名称(如 pwd
或 a.out
)或不以 she-bang 开头的可执行脚本,您应该使用 execlp
而不是 execl
.
exec[lv]p[e]
函数做一些 shell 做的事情(比如查看 PATH
),但不是全部(比如 运行 多个命令或扩展变量):这就是 system(3)
或 popen(3)
等函数将命令传递给 /bin/sh -c
的原因。请注意,它是 /bin/sh
,而不是用户的登录名 shell 或所使用环境中的 $SHELL
。
If you exec sh -c a.out
instead of just a.out
itself, does the actual a.out
process end up being a "grandchild" process and not a child process?
只有一些 shell 像 dash
。不适用于 bash
、ksh93
、mksh
、zsh
、yash
、busybox
等,它们将直接执行 a.out
分叉并等待它。
我正在 https://opensource.apple.com/source/Libc/Libc-167/gen.subproj/popen.c.auto.html 研究 Apple 对 popen()
的实施,并注意到他们 execl(_PATH_BSHELL, "sh", "-c", command, NULL)
而不是 execl(_PATH_BSHELL, command, NULL)
。
为什么你想要(或者你应该)执行一个可执行文件,例如a.out
通过 sh -c
而不仅仅是可执行文件本身?
如果您执行 sh -c a.out
而不是 a.out
本身,实际的 a.out
进程是否最终成为“孙子”进程而不是 子进程进程?
Why would you want to (or should you) exec an executable, e.g.
a.out
viash -c
instead of just the executable itself?
popen()
设计用于 运行 shell 命令,包括 shell 语法,如 >
重定向、|
管道和 &&
命令链。它需要通过 sh -c
传递字符串以支持这些构造。如果没有,这些语法特征将作为参数逐字传递给相关程序。
例如,popen("make clean && make")
应该触发两次 make
调用。没有 sh -c
它会用三个参数调用 make
一次,就好像一个人输入了
$ make clean '&&' make
在航站楼。
If you exec
sh -c a.out
instead of justa.out
itself, does the actuala.out
process end up being a "grandchild" process and not a child process?
是的,没错。在当前进程和a.out
之间会有一个sh
进程。
that they do
execl(_PATH_BSHELL, "sh", "-c", command, NULL)
instead ofexecl(_PATH_BSHELL, command, NULL)
后者不会直接执行 command
,但是 _PATH_BSHELL
(/bin/sh
) 的 [=15=]
设置为 command
和 没有参数,导致 shell 期待来自其标准输入的命令。
此外,该语法依赖于 NULL
被定义为显式指针(例如 ((void*)0)
),而不仅仅是 0
,这在任何地方都无法保证。虽然他们可以在他们的实现中做到这一点(因为他们控制所有 headers),但这不是您应该在应用程序代码中做的。
不,execl(command, command, (void*)NULL)
也不会直接执行 command
,除非 command
是 a) 一个完整路径并且 b) 可执行格式(二进制或以 she-bang #!
开头的脚本——后者是 non-standard 扩展)。如果 command
是要在 PATH
中查找的简单命令名称(如 pwd
或 a.out
)或不以 she-bang 开头的可执行脚本,您应该使用 execlp
而不是 execl
.
exec[lv]p[e]
函数做一些 shell 做的事情(比如查看 PATH
),但不是全部(比如 运行 多个命令或扩展变量):这就是 system(3)
或 popen(3)
等函数将命令传递给 /bin/sh -c
的原因。请注意,它是 /bin/sh
,而不是用户的登录名 shell 或所使用环境中的 $SHELL
。
If you exec
sh -c a.out
instead of justa.out
itself, does the actuala.out
process end up being a "grandchild" process and not a child process?
只有一些 shell 像 dash
。不适用于 bash
、ksh93
、mksh
、zsh
、yash
、busybox
等,它们将直接执行 a.out
分叉并等待它。