Qual é a diferença entre os backticks, sistema e exec do Perl?

237

Alguém por favor pode me ajudar? No Perl, qual é a diferença entre:

exec "command";

e

system("command");

e

print `command`;

Existem outras maneiras de executar comandos shell também?

rlbond
fonte
8
Quase uma duplicata exata de stackoverflow.com/questions/797127/… , exceto que este possui exec e o outro possui pipes.
Michael Myers

Respostas:

268

exec

executa um comando e nunca retorna . É como uma returndeclaração em uma função.

Se o comando não for encontrado, execretornará false. Ele nunca retorna verdadeiro, porque se o comando for encontrado, ele nunca retornará. Também há nenhum ponto em voltar STDOUT, STDERRou status de saída do comando. Você pode encontrar documentação sobre isso perlfunc, porque é uma função.

sistema

executa um comando e seu script Perl continua após a conclusão do comando.

O valor de retorno é o status de saída do comando. Você pode encontrar documentação sobre isso em perlfunc.

backticks

like systemexecuta um comando e seu script perl continua após a conclusão do comando.

Ao contrário systemdo valor de retorno é STDOUTdo comando. qx//é equivalente a backticks. Você pode encontrar documentação sobre isso perlop, porque diferente systeme execé um operador.


Outras maneiras

O que está faltando acima é uma maneira de executar um comando de forma assíncrona. Isso significa que seu script perl e seu comando são executados simultaneamente. Isso pode ser realizado com open. Ele permite que você leia STDOUT/ STDERRescreva no STDINseu comando. Depende da plataforma.

Existem também vários módulos que podem facilitar essas tarefas. Existe IPC::Open2e IPC::Open3e IPC::Run, assim como Win32::Process::Createse você estiver no Windows.

Ludwig Weinzierl
fonte
1
Eu acho que você quer dizer s / perlcunc / perlfunc / ... também a documentação do perlipc entra em grande profundidade sobre a abertura de tubos.
ephemient
7
perlcunc, talvez este será o meu novo nome nick ;-)
Ludwig Weinzierl
8
Para o registro, backticks e qx [] também preenchem $? (o valor de retorno do SO).
jjohn
167

No uso geral I system, open, IPC::Open2, ou IPC::Open3dependendo do que eu quero fazer. O qx//operador, embora simples, é muito restritivo em sua funcionalidade para ser muito útil fora de hacks rápidos. Eu acho openmuito mais prático.

system: execute um comando e aguarde o retorno

Use systemquando quiser executar um comando, não se importe com a saída e não queira que o script Perl faça nada até que o comando termine.

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

ou

#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//ou `` : execute um comando e capture seu STDOUT

Use qx//quando quiser executar um comando, capture o que ele grava no STDOUT e não deseja que o script Perl faça nada até que o comando seja concluído.

#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: substitua o processo atual por outro processo.

Use execjunto forkquando quiser executar um comando, não se importe com a saída e não espere que ele retorne. systemé realmente apenas

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
}

Você também pode querer ler o waitpide perlipcmanuais.

open: execute um processo e crie um canal para seu STDIN ou STDERR

Use openquando desejar gravar dados no STDIN de um processo ou ler dados do STDOUT de um processo (mas não os dois ao mesmo tempo).

#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 : execute um processo e crie um canal para STDIN e STDOUT

Use IPC::Open2quando precisar ler e gravar em STDIN e STDOUT de um 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 : execute um processo e crie um canal para STDIN, STDOUT e STDERR

use IPC::Open3quando precisar capturar todos os três identificadores de arquivo padrão do processo. Eu escreveria um exemplo, mas funciona principalmente da mesma maneira que IPC :: Open2, mas com uma ordem ligeiramente diferente dos argumentos e um terceiro identificador de arquivo.

Chas. Owens
fonte
Resposta muito informativa e atualizada. Obrigado @ chas-owens
Jassi
IPC :: Open3 é de nível muito baixo para a maioria dos usos. IPC :: Run3 e IPC :: Run são geralmente muito mais apropriados.
Ikegami
17

Deixe-me citar os manuais primeiro:

perldoc exec () :

A função exec executa um comando do sistema e nunca retorna - use system em vez de exec se desejar que ele retorne

sistema perldoc () :

Faz exatamente a mesma coisa que o exec LIST, exceto que uma bifurcação é feita primeiro e o processo pai aguarda a conclusão do processo filho.

Ao contrário do exec e do sistema , os backticks não fornecem o valor de retorno, mas o STDOUT coletado.

perldoc `String` :

Uma sequência que é (possivelmente) interpolada e depois executada como um comando do sistema com / bin / sh ou seu equivalente. Curingas, canais e redirecionamentos do Shell serão respeitados. A saída padrão coletada do comando é retornada ; erro padrão não é afetado.


Alternativas:

Em cenários mais complexos, nos quais você deseja buscar STDOUT, STDERR ou o código de retorno, é possível usar módulos padrão conhecidos como IPC :: Open2 e IPC :: Open3 .

Exemplo:

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

Por fim, vale a pena olhar o IPC :: Run from the CPAN…

Benedikt Waldvogel
fonte
3
Esta é uma resposta rude. Você deve tentar ser útil sem a raiva.
213 Shane C. Mason
1
Eu acho que ele estava apenas fazendo uma referência ao antigo RTFM: P
v3.
não era grosseiro realmente;) removeu o f-word no entanto, para evitar qualquer mal-entendido ...
Benedikt Waldvogel
2
Eu certamente não a interpretei como sendo rude. Brusco, talvez, mas essa não é uma pergunta altamente inteligente que requer uma resposta ponderada.
ephemient
11

Qual é a diferença entre os backticks de Perl ( `) systeme exec?

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

exec

execexecuta um comando e nunca retoma o script Perl. É para um script como uma returndeclaração é para uma função.

Se o comando não for encontrado, execretorna false. Ele nunca retorna verdadeiro, porque se o comando for encontrado, ele nunca retornará. Também há nenhum ponto em voltar STDOUT, STDERRou status de saída do comando. Você pode encontrar documentação sobre isso em perlfunc , porque é uma função.

Por exemplo:

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

No código acima, existem três printinstruções, mas, devido à execsaída do script, apenas a primeira instrução de impressão é executada. Além disso, a execsaída do comando não está sendo atribuída a nenhuma variável.

Aqui, apenas você está obtendo a saída da primeira printinstrução e executando o lscomando na saída padrão.

system

systemexecuta um comando e seu script Perl é retomado após a conclusão do comando. O valor de retorno é o status de saída do comando. Você pode encontrar documentação sobre isso em perlfunc .

Por exemplo:

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

No código acima, há três printinstruções. Como o script é retomado após o systemcomando, todas as três instruções de impressão são executadas.

Além disso, o resultado da execução system é atribuído data2, mas o valor atribuído é 0(o código de saída de ls).

Aqui, você obtém a saída da primeira printinstrução, depois a do lscomando, seguida pelas saídas das duas últimas printinstruções na saída padrão.

retalhos ( `)

Por exemplo system, incluir um comando nos backticks executa esse comando e seu script Perl é retomado após a conclusão do comando. Em contraste com system, o valor de retorno é STDOUTdo comando. qx//é equivalente a backticks. Você pode encontrar documentação sobre isso no perlop , porque diferente do sistema e exec, é um operador.

Por exemplo:

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

No código acima, há três printinstruções e todas as três estão sendo executadas. A saída de lsnão será padronizada diretamente, mas atribuída à variável data2e depois impressa pela instrução final print.

linuxtestside
fonte
Melhor explicação com o exemplo. Muito obrigado.
Arslan Anwar
2

A diferença entre 'exec' e 'system' é que exec substitui seu programa atual por 'command' e NUNCA retorna ao seu programa. O sistema, por outro lado, bifurca e executa 'command' e retorna o status de saída de 'command' quando terminar de executar. O back tick executa 'command' e, em seguida, retorna uma string que representa seu padrão (o que quer que fosse impresso na tela)

Você também pode usar o popen para executar comandos do shell e acho que existe um módulo shell - 'use shell' que fornece acesso transparente aos comandos típicos do shell.

Espero que esclareça isso para você.

Shane C. Mason
fonte
Talvez você queira dizer use Shell;( search.cpan.org/dist/Shell/Shell.pm )? Não é amplamente instalado, nem é aplicável à questão, eu acho ...
ephemient
1
A última parte de sua pergunta foi "existem outras maneiras de executar comandos do shell também" - o Shell é outra maneira de executar comandos do shell.
217 Shane C. Mason
2
Os documentos afirmam especificamente "Este pacote está incluído como um caso de demonstração, ilustrando alguns recursos do Perl. Ele não deve ser usado para programas de produção. Embora ele forneça uma interface simples para obter a saída padrão de comandos arbitrários, pode haver melhor maneiras de conseguir o que você precisa. "
Chas. Owens
2
Novamente, ele respondeu a sua pergunta 'existem outras maneiras'
Shane C. Mason
Maneiras ruins e não suportadas não devem ser dadas sem avisos de que são ruins e não suportadas.
Chas. Owens