bash是否支持类似于C的fork()的分支?


25

我有一个脚本,我想一次分叉,以便同一脚本的两个副本正在运行。

例如,我希望存在以下bash脚本:

echo $$
do_fork()
echo $$

如果此bash脚本确实存在,则预期输出为:

<ProcessA PID>
<ProcessB PID>
<ProcessA PID>

要么

<ProcessA PID>
<ProcessA PID>
<ProcessB PID>

我可以代替“ do_fork()”来获得这种输出,还是使bash脚本执行类似于C的fork?

Answers:


23

是。分叉的拼写是&

echo child & echo parent

可能使您感到困惑的$$不是外壳程序进程的PID,而是原始外壳程序进程的PID 。这样做的目的在于,它$$是Shell脚本的特定实例的唯一标识符:它在脚本执行期间不会更改,并且与$$任何其他同时运行的脚本不同。获取shell进程的实际PID的一种方法是sh -c 'echo $PPID'

Shell中的控制流与C不同。如果在C中,您将编写

first(); fork(); second(); third();

那么等效的外壳是

after_fork () { second; third; }
first; after_fork & after_fork

简单的外壳形式first; child & parent对应于通常的C习惯用法

first(); if (fork()) parent(); else child();

&并且$$在每个Bourne样式的shell和(t)csh中都以这种方式存在和表现。$PPID在原始的Bourne外壳中不存在,但在POSIX中存在(因此位于ash,bash,ksh,zsh等)。


3
但这基本上是“ fork + exec”,而不仅仅是fork。
mattdm 2011年

@mattdm:嗯?&是fork,不涉及执行程序。当您启动外部命令时,将使用Fork + exec。
吉尔(Gilles)'所以

@mattdm:啊,我想我知道Cory的意思了。没有exec,但是两种语言的控制流程确实不同。
吉尔(Gilles)'所以

1
@Gilles:bash控制运算符&启动一个子shell,在该子shell中执行给定命令。前叉+执行 您不能只放置&没有前面的命令来执行。
mattdm 2011年

5
好吧,如果“ Forking ispelled&”是正确的说法,那么您可以自己加上&一行。但是你不能。这并不意味着“在这里叉子”。它的意思是“在子外壳程序的后台执行前面的命令”。
mattdm 2011年

10

是的,它称为subshel​​ls。括号内的Shell代码作为子Shell(分支)运行。但是,第一个外壳通常会等待孩子完成。您可以使用&终止符使其异步。看到这样的效果:

#!/bin/bash

(sleep 2; echo "subsh 1")&
echo "topsh"

$ bash subsh.sh


5
括号会创建一个子外壳,但这是fork + wait。&是叉子。如果您想在子进程中执行多个管道,则只需使用花括号(无需创建子进程即可执行分组)就足够了:{ sleep 2; echo child; } &
Gilles'SO-别成为邪恶

6

没有本机bash(或者据我所知,没有其他任何典型的* nix shell)的方式。有很多方法可以生成派生的进程,这些进程可以异步执行其他操作,但是我认为没有任何事情可以遵循fork()系统调用的确切语义。

典型的方法是让您的顶级脚本派生出仅执行您要拆分的工作的助手。如果您这样做$0 $@ &,则将重新开始,并且需要以某种方式弄清楚。

我实际上已经开始思考可能会做到这一点的几种巧妙方法。

但是,在我的头脑不被这吓倒之前,我认为一个不错的规则是:如果您试图在shell中编写某些东西,并且它充满了聪明的窍门,并且您希望有更多的语言功能,那么您应该花点时间来切换到一种真正的编程语言


2
尽管您的观点很好理解-bash的语法可以说很难,并且缺少Perl或Python更为优雅的数据结构和功能,但bash 在其领域中是真实存在的。它是一种特定于领域的语言,在许多情况下,我认为它比Python更好(更简洁,更简单)。您可以管理一个庞大的系统并且不了解Python吗?是。您能做到而又不熟悉bash编程吗?我不想尝试。经过30年的Shell编程,我告诉您它是真实存在的。是的,我会说Python。但是不要混淆年轻人。
Mike S

2
就是说,从技术上讲,我更喜欢这个答案。说“&”是用户问题的答案,“我分叉所以运行了相同脚本的两个副本”,这在我看来令人困惑。根据bash手册,“&”的作用是“ ...在子shell的后台执行[given]命令”。它必须终止一个命令,并且确实涉及派生(在技术上,在Linux中,它是clone()),但是此时同一脚本的两个副本未运行。
Mike S
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.