首页 > 解决方案 > 什么时候应该使用 system(3) 来运行外部进程?

问题描述

C 提供了使用shellsystem运行子进程的标准函数,并且许多语言提供了类似的函数,例如AWKPerl(带有单个参数)和PHP。有时这些功能被批评为不适合一般使用,无论是出于安全原因还是因为外壳不可移植或不是交互式使用的外壳。

其他一些语言似乎也同意:它们只提供了一种在没有 shell 的情况下运行进程的方法,例如Java(它标记任何单个字符串参数本身)和Tcl。Python 提供了直接的包装器复杂的替代品,可以避免使用 shell 并明确推荐后者(就像用户社区一样)。

当然,对于许多应用程序来说,shell 是不必要的复杂性;运行外部进程可能会带来死锁孤儿进程、不明确的退出状态和文件描述符共享等问题,并且在运行mkdirecho $VAR. 但是,假设它的system存在是有原因的,那么什么时候使用它是正确的工具?

标签: pythoncos.system

解决方案


即使假设一个用例适合运行外部进程,特别是通过 shell 运行一个(不能像 with 一样过滤输出popen),对于 C 和 Python(使用实际的C system(3)),还有额外的警告。POSIX为 :指定了额外的行为system:它在执行过程中忽略 SIGINTSIGQUIT阻塞。SIGCHLD基本原理是用户(可以从终端发送SIGINT和发送)在执行期间与子进程交互,而不是父进程,并且必须在不受应用程序干扰的情况下为其子进程处理。SIGQUITsystemSIGCHLD

这直接暗示了问题的答案:system只有在

  1. 用户直接要求执行特定的 shell 命令(例如 with !in less),并且
  2. 应用程序不需要对在此期间退出的任何其他子进程做出反应(例如,它不应该是多线程的)。

如果 #1 不满足,用户可能会发送一个终端信号,期望它终止整个进程并让它只杀死(如果不是不可见的话,意外的)子进程。Linux 手册页特别注意在用户无法中断的循环中使用它。可能会注意到一个孩子已经退出并重新启动它,但这是不可靠的,因为某些程序(例如Python)在接收到某些信号时而exit不是重新启动它以指示它们退出的原因 - 并且因为 shell(由!)将退出状态与信号终止状态混为一谈。system

在 Python 中,错误处理问题因os.system遵循 C 退出状态(读取:错误代码)约定而不是将失败报告为异常而导致用户忽略子项的退出状态这一事实更加复杂。


推荐阅读