Qual è la differenza tra i backtick, il sistema e il exec di Perl?


237

Qualcuno può aiutarmi? In Perl, qual è la differenza tra:

exec "command";

e

system("command");

e

print `command`;

Ci sono altri modi per eseguire anche i comandi di shell?


8
Quasi un duplicato esatto di stackoverflow.com/questions/797127/… , tranne per il fatto che questo ha exec e l'altro ha pipe.
Michael Myers

Risposte:


268

exec

esegue un comando e non ritorna mai . È come returnun'affermazione in una funzione.

Se il comando non viene trovato, execrestituisce false. Non ritorna mai vero, perché se il comando viene trovato non ritorna mai affatto. V'è anche inutile tornare STDOUT, STDERRo lo stato di uscita del comando. Puoi trovare la documentazione a riguardo in perlfunc, perché è una funzione.

sistema

esegue un comando e lo script Perl continua dopo il completamento del comando.

Il valore restituito è lo stato di uscita del comando. Puoi trovare la documentazione al riguardo in perlfunc.

apici inversi

like systemesegue un comando e il tuo script perl continua dopo che il comando è terminato.

Al contrario systemdel valore restituito è STDOUTdel comando. qx//equivale a backtick. Puoi trovare la documentazione a riguardo perlop, perché a differenza di systemed execè un operatore.


Altri modi

Ciò che manca da quanto sopra è un modo per eseguire un comando in modo asincrono. Ciò significa che lo script perl e il comando vengono eseguiti contemporaneamente. Questo può essere realizzato con open. Ti permette di leggere STDOUT/ STDERRe scrivere sul STDINtuo comando. Tuttavia, dipende dalla piattaforma.

Esistono anche diversi moduli che possono facilitare queste attività. C'è IPC::Open2e IPC::Open3e IPC::Run, così come Win32::Process::Createse sei su Windows.


1
Penso che intendi s / perlcunc / perlfunc / ... anche la documentazione di perlipc approfondisce le aperture di apertura.
effimero

7
perlcunc, forse questo sarà il mio nuovo soprannome ;-)
Ludwig Weinzierl,

8
Per la cronaca, backtick e qx [] popolano anche $? (il valore di ritorno del sistema operativo).
Giovanni

167

In uso generale I system, open, IPC::Open2, oppure IPC::Open3a seconda di ciò che voglio fare. L' qx//operatore, sebbene semplice, è troppo vincolante nella sua funzionalità per essere molto utile al di fuori di hack rapidi. Trovo openmolto più maneggevole.

system: esegui un comando e attendi che ritorni

Utilizzare systemquando si desidera eseguire un comando, non preoccuparsi del suo output e non si desidera che lo script Perl faccia nulla fino al termine del comando.

#doesn't spawn a shell, arguments are passed as they are
system("command", "arg1", "arg2", "arg3");

o

#spawns a shell, arguments are interpreted by the shell, use only if you
#want the shell to do globbing (e.g. *.txt) for you or you want to redirect
#output
system("command arg1 arg2 arg3");

qx//oppure `` : esegui un comando e acquisisci il suo STDOUT

Utilizzare qx//quando si desidera eseguire un comando, acquisire ciò che scrive su STDOUT e non si desidera che lo script Perl esegua alcuna operazione fino al termine del comando.

#arguments are always processed by the shell

#in list context it returns the output as a list of lines
my @lines = qx/command arg1 arg2 arg3/;

#in scalar context it returns the output as one string
my $output = qx/command arg1 arg2 arg3/;

exec: sostituisce il processo corrente con un altro processo.

Utilizzare execinsieme a forkquando si desidera eseguire un comando, non preoccuparsi del suo output e non si desidera attendere che ritorni. systemè davvero giusto

sub my_system {
    die "could not fork\n" unless defined(my $pid = fork);
    return waitpid $pid, 0 if $pid; #parent waits for child
    exec @_; #replace child with new process
}

Potresti anche voler leggere i manuali waitpide perlipc.

open: esegue un processo e crea una pipe nel suo STDIN o STDERR

Utilizzare openquando si desidera scrivere dati nello STDIN di un processo o leggere i dati dallo STDOUT di un processo (ma non entrambi contemporaneamente).

#read from a gzip file as if it were a normal file
open my $read_fh, "-|", "gzip", "-d", $filename
    or die "could not open $filename: $!";

#write to a gzip compressed file as if were a normal file
open my $write_fh, "|-", "gzip", $filename
    or die "could not open $filename: $!";

IPC :: Open2 : esegue un processo e crea una pipe per STDIN e STDOUT

Utilizzare IPC::Open2quando è necessario leggere e scrivere su STDIN e STDOUT di un processo.

use IPC::Open2;

open2 my $out, my $in, "/usr/bin/bc"
    or die "could not run bc";

print $in "5+6\n";

my $answer = <$out>;

IPC :: Open3 : esegue un processo e crea una pipe su STDIN, STDOUT e STDERR

utilizzare IPC::Open3quando è necessario acquisire tutti e tre gli handle di file standard del processo. Vorrei scrivere un esempio, ma funziona principalmente allo stesso modo di IPC :: Open2, ma con un ordine leggermente diverso rispetto agli argomenti e un terzo file gestito.


Risposta molto istruttiva e aggiornata. Grazie @ chas-owens
Jassi

IPC :: Open3 è di livello troppo basso per la maggior parte degli usi. IPC :: Run3 e IPC :: Run sono generalmente molto più appropriati.
ikegami,

17

Vorrei prima citare i manuali:

perldoc exec () :

La funzione exec esegue un comando di sistema e non ritorna mai - usa il sistema invece di exec se vuoi che ritorni

sistema perldoc () :

Fa esattamente la stessa cosa di exec LIST, tranne per il fatto che un fork viene eseguito per primo e il processo parent attende il completamento del processo child.

Contrariamente a exec e system , i backtick non danno il valore di ritorno ma lo STDOUT raccolto.

perldoc `String` :

Una stringa che è (possibilmente) interpolata e quindi eseguita come comando di sistema con / bin / sh o suo equivalente. I caratteri jolly Shell, i pipe e i reindirizzamenti verranno rispettati. Viene restituito l'output standard raccolto del comando ; l'errore standard non è interessato.


alternative:

In scenari più complessi, in cui si desidera recuperare STDOUT, STDERR o il codice di ritorno, è possibile utilizzare moduli standard ben noti come IPC :: Open2 e IPC :: Open3 .

Esempio:

use IPC::Open2;
my $pid = open2(\*CHLD_OUT, \*CHLD_IN, 'some', 'cmd', 'and', 'args');
waitpid( $pid, 0 );
my $child_exit_status = $? >> 8;

Infine, vale la pena guardare anche IPC :: Run dal CPAN ...


3
Questa è una risposta scortese. Dovresti cercare di essere d'aiuto senza rabbia.
Shane C. Mason,

1
Penso che stesse solo facendo riferimento al vecchio RTFM: P
v3.

non volevo dire maleducato in realtà;) rimosso la f-word, per evitare equivoci ...
Benedikt Waldvogel,

2
Di certo non l'ho interpretato come maleducato. Forse brusco, ma questa non è una domanda molto intelligente che richiede una risposta ponderata.
effimero

11

Qual è la differenza tra i backtick di Perl ( `) system, e exec?

exec -> exec "command"; ,
system -> system("command"); and 
backticks -> print `command`;

exec

execesegue un comando e non riprende mai lo script Perl. È per uno script come returnun'istruzione è per una funzione.

Se il comando non viene trovato, execrestituisce false. Non ritorna mai vero, perché se il comando viene trovato, non ritorna mai affatto. V'è anche inutile tornare STDOUT, STDERRo lo stato di uscita del comando. Puoi trovare la documentazione a riguardo in perlfunc , perché è una funzione.

Per esempio:

#!/usr/bin/perl
print "Need to start exec command";
my $data2 = exec('ls');
print "Now END exec command";
print "Hello $data2\n\n";

Nel codice sopra, ci sono tre printistruzioni, ma a causa di execlasciare lo script, viene eseguita solo la prima istruzione di stampa. Inoltre, l' execoutput del comando non viene assegnato a nessuna variabile.

Qui, solo tu stai ottenendo solo l'output della prima printistruzione e l'esecuzione del lscomando su standard out.

system

systemesegue un comando e il tuo script Perl viene ripreso al termine del comando. Il valore restituito è lo stato di uscita del comando. Puoi trovare la documentazione al riguardo in perlfunc .

Per esempio:

#!/usr/bin/perl
print "Need to start system command";
my $data2 = system('ls');
print "Now END system command";
print "Hello $data2\n\n";

Nel codice sopra, ci sono tre printistruzioni. Quando lo script viene ripreso dopo il systemcomando, vengono eseguite tutte e tre le istruzioni di stampa.

Inoltre, il risultato dell'esecuzione system è assegnato a data2, ma il valore assegnato è 0(il codice di uscita da ls).

Qui, stai ottenendo l'output della prima printistruzione, quindi quello del lscomando, seguito dagli output delle ultime due printistruzioni sullo standard out.

backticks ( `)

Ad esempio system, racchiudendo un comando nei backtick viene eseguito quel comando e il tuo script Perl viene ripreso al termine del comando. Al contrario system, il valore restituito è STDOUTdel comando. qx//equivale a backtick. Puoi trovare la documentazione a riguardo in perlop , perché a differenza del sistema e exec, è un operatore.

Per esempio:

#!/usr/bin/perl
print "Need to start backticks command";
my $data2 = `ls`;
print "Now END system command";
print "Hello $data2\n\n";

Nel codice sopra, ci sono tre printistruzioni e tutte e tre sono in esecuzione. L'output di lsnon verrà standardizzato direttamente, ma assegnato alla variabile data2e quindi stampato dall'istruzione di stampa finale.


Migliore spiegazione con l'esempio. Molte grazie.
Arslan Anwar,

2

La differenza tra 'exec' e 'system' è che exec sostituisce il tuo programma attuale con 'command' e MAI ritorna al tuo programma. il sistema, d'altra parte, esegue il fork ed esegue 'command' e restituisce lo stato di uscita di 'command' al termine dell'esecuzione. Il segno di spunta indietro esegue 'command' e quindi restituisce una stringa che rappresenta il suo standard out (qualunque cosa avrebbe stampato sullo schermo)

Puoi anche usare popen per eseguire i comandi della shell e penso che esista un modulo della shell: "usa la shell" che ti dà accesso trasparente ai tipici comandi della shell.

Spero che questo ti chiarisca.


Forse intendi use Shell;( search.cpan.org/dist/Shell/Shell.pm )? Non è ampiamente installato, né applicabile alla domanda, penso ...
effimero

1
L'ultima parte della sua domanda era "ci sono altri modi per eseguire anche i comandi della shell" - Shell è un altro modo per eseguire i comandi della shell.
Shane C. Mason,

2
I documenti dichiarano specificamente "Questo pacchetto è incluso come vetrina, illustrando alcune funzionalità di Perl. Non dovrebbe essere usato per programmi di produzione. Sebbene fornisca una semplice interfaccia per ottenere l'output standard di comandi arbitrari, potrebbe esserci di meglio modi per raggiungere ciò di cui hai bisogno ".
Chas. Owens,

2
Ancora una volta, ha risposto alla sua domanda "ci sono altri modi"
Shane C. Mason,

I modi sbagliati e non supportati non dovrebbero essere forniti senza avvertimenti che sono cattivi e non supportati.
Chas. Owens,
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.