bash 中(命令)和命令之间的区别

bash 中(命令)和命令之间的区别

在调查关键字stderr重定向问题和问题的标准解决方案时,我遇到了另一个问题。描述给出了bashtimeman bash(list) 复合命令list 在子shell环境中执行。现在,正如您从小程序的执行中看到的那样hello- 它进行了简单的调用,看起来命令行和命令行system("ps -opid,ppid,comm")之间没有任何区别。这让我感到惊讶。不过我知道当命令是内置命令时会有区别。在这种情况下,如果没有括号,则不会发生分叉,但如果内置命令周围有括号,则会发生分叉。我错过了什么吗?(./hello)./hello

18:59:13 -> echo $$
5323
19:34:30 -> ./hello
hello world from process ID 8657, parent ID 5323
  PID  PPID COMM
 5323  5322 -bash
 8657  5323 ./hello
19:42:34 -> (./hello)
hello world from process ID 8977, parent ID 5323
  PID  PPID COMM
 5323  5322 -bash
 8977  5323 ./hello
19:42:43 -> time (./hello)
hello world from process ID 8985, parent ID 8984
  PID  PPID COMM
 5323  5322 -bash
 8984  5323 -bash
 8985  8984 ./hello

real    0m0.021s
user    0m0.003s
sys 0m0.004s
19:42:53 -> (time ./hello)
hello world from process ID 9000, parent ID 8999
  PID  PPID COMM
 5323  5322 -bash
 8999  5323 -bash
 9000  8999 ./hello

real    0m0.030s
user    0m0.003s
sys 0m0.005s
19:43:05 ->

答案1

不保证子 shell 在单独的进程中运行。这只是通常的实现。

子 shell 的定义是 shell 必须确保子 shell 不会更改其父 shell 的状态:它不能影响父 shell 的变量、定义的函数、别名、选项、历史记录、限制等。最简单的方法是是在单独的进程中运行子 shell,所以通常会发生这种情况。但是,如果 shell 可以确保子 shell 不会影响父 shell 中的任何内容,则它不必运行单独的进程。

对于大多数 sh 实现,除了运行外部命令之外不执行任何操作的子 shell 不会分叉两次。

for sh in dash bash ksh93 mksh zsh; do printf "%6s " "$sh"; "$sh" -c '(perl -e "print getppid()"); echo " $$"'; done
  dash 945 945
  bash 947 947
 ksh93 949 949
  mksh 951 951
   zsh 953 953

一旦您执行了更复杂的操作,bash 就会分叉子 shell,并再次分叉外部命令。其他一些 shell 不会分叉(子)shell 的最后一个命令(除非有陷阱)。

for sh in dash bash ksh93 mksh zsh; do printf "%6s " "$sh"; "$sh" -c '(true; perl -e "print getppid()"); echo " $$"'; done
  dash 1306 1306
  bash 1309 1308
 ksh93 1311 1311
  mksh 1314 1313
   zsh 1316 1316

ATT ksh ( ksh93) 比其他 shell 优化更多。在我进行比较的五个程序中,它是唯一一个通过在同一进程中创建单独的数据结构来跟踪子 shell 中不断变化的数据来进行优化的程序。

for sh in dash bash ksh93 mksh zsh; do printf "%6s " "$sh"; "$sh" -c '(perl -e "print getppid()"; /bin/true); echo " $$"'; done
  dash 3082 3081
  bash 3085 3084
 ksh93 3088 3088
  mksh 3092 3091
   zsh 3096 3095

有些事情甚至会强制 ATT ksh 为子 shell 创建子进程,例如更改进程限制。

for sh in dash bash ksh93 mksh zsh; do printf "%6s " "$sh"; "$sh" -c '(ulimit -n 42; perl -e "print getppid()"; /bin/true); echo " $$"'; done
  dash 4504 4503
  bash 4507 4506
 ksh93 4511 4510
  mksh 4515 4514
   zsh 4519 4518

相关内容