Bash supporta il fork come C's fork ()?


25

Ho una sceneggiatura che vorrei rovesciare a un certo punto, quindi sono in esecuzione due copie della stessa sceneggiatura.

Ad esempio, vorrei che esistesse il seguente script bash:

echo $$
do_fork()
echo $$

Se questo script bash esistesse veramente, l'output previsto sarebbe:

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

o

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

C'è qualcosa che posso mettere al posto di "do_fork ()" per ottenere questo tipo di output o per fare in modo che lo script bash esegua un fork simile a C?

Risposte:


23

Sì. Forking è scritto &:

echo child & echo parent

Ciò che può confonderti è che $$non è il PID del processo di shell, è il PID del processo di shell originale . Il punto di farlo in questo modo è che $$è un identificatore univoco per una particolare istanza dello script di shell: non cambia durante l'esecuzione dello script ed è diverso da $$qualsiasi altro script in esecuzione contemporaneamente. Un modo per ottenere il PID effettivo del processo shell è sh -c 'echo $PPID'.

Il flusso di controllo nella shell non è lo stesso di C. Se in C dovresti scrivere

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

allora è un equivalente shell

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

La semplice forma a conchiglia first; child & parentcorrisponde al solito linguaggio C

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

&ed $$esiste e si comporta in questo modo in ogni shell in stile Bourne e in (t) csh. $PPIDnon esisteva nella shell originale Bourne ma è in POSIX (quindi è in ash, bash, ksh, zsh, ...).


3
Ma questo è fondamentalmente "fork + exec", non solo fork.
Mattdm,

@mattdm: Uh? &è fork, non c'è nessun dirigente coinvolto. Fork + exec è quando si lancia un comando esterno.
Gilles 'SO- smetti di essere malvagio' il

@mattdm: Ah, penso di vedere a cosa sta arrivando Cory. No exec, ma le due lingue hanno un flusso di controllo diverso.
Gilles 'SO- smetti di essere malvagio' il

1
@Gilles: l'operatore di controllo bash &avvia una sottostruttura in cui viene eseguito il comando dato. Fork + exec. Non puoi semplicemente mettere &senza alcun comando precedente da eseguire.
Mattdm,

5
Bene, se "Forking è scritto e" erano una vera affermazione, si potrebbe mettere &su una linea da solo. Ma non puoi. Non significa "fork qui". Significa "eseguire il comando precedente in background in una subshell".
Mattdm,

10

Sì, si chiama subshells . Il codice shell tra parentesi viene eseguito come subshell (fork). Tuttavia, la prima shell normalmente attende il completamento del figlio. Puoi renderlo asincrono usando il &terminatore. Guardalo in azione con qualcosa del genere:

#!/bin/bash

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

$ bash subsh.sh


5
Le parentesi creano una subshell, ma questo è fork + wait. &è solo fork. Se si desidera eseguire più di una pipeline nel processo figlio, è sufficiente utilizzare le parentesi graffe (che eseguono il raggruppamento senza creare un processo figlio):{ sleep 2; echo child; } &
SO di Gilles- smettere di essere malvagio '18

6

Non esiste un modo bash nativo (o, per quanto ne sappia, qualsiasi altro tipico * nix shell) di farlo. Esistono molti modi per generare processi a forcella che fanno qualcos'altro in modo asincrono, ma non credo che ci sia qualcosa che segue l'esatta semantica della chiamata di sistema fork ().

L'approccio tipico sarebbe quello di far sì che il tuo script di livello superiore produca helper che svolgono esattamente il lavoro che desideri dividere. Se lo fai $0 $@ &o qualsiasi altra cosa, ricomincerai dall'inizio e dovrai capirlo in qualche modo.

In realtà sto iniziando a pensare a diversi modi intelligenti in cui uno potrebbe fare proprio questo ...

Ma , prima che il mio cervello sia troppo preso da questo, penso che una regola abbastanza buona sia: se stai cercando di scrivere qualcosa in shell e si sta riempiendo di trucchi intelligenti e desideri più funzionalità linguistiche, è tempo di cambiare ad un vero linguaggio di programmazione .


2
Sebbene il tuo punto sia ben preso, la sintassi di Bash è discutibilmente difficile e manca le strutture dati e le funzionalità più eleganti di Perl o Python, bash è reale come diventa nel suo dominio . È un linguaggio specifico del dominio, e direi ancora meglio (più conciso, più semplice) di Python, ad esempio, in molti casi. Riesci ad amministrare una stanza piena di sistemi e non conosci Python? Sì. Riesci a farlo e non conosci un pizzico di bash [programmazione]? Non vorrei provare. Dopo 30 anni di programmazione della shell, ti dico che è reale come si arriva. E sì, parlo Python. Ma non confondere i giovani.
Mike S,

2
Detto questo, tecnicamente mi piace di più questa risposta. Dire che "&" è la risposta alla domanda dell'utente, "biforcarsi ad un certo punto in modo che due copie dello stesso script siano in esecuzione" mi sembra confuso. Ciò che "&" fa, secondo il manuale di bash, è "... esegue il comando [dato] in background in una subshell." Deve terminare un comando e implica un fork (tecnicamente, in Linux, un clone ()), ma a quel punto non sono in esecuzione due copie dello stesso script.
Mike S,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.