В чем разница между бэкстиками Perl, системой и exec?

187

Может кто-нибудь мне помочь? В Perl, в чем разница между:

exec "command";

и

system("command");

и

print `command`;

Есть ли другие способы запуска команд оболочки?

  • 8
    Почти точная копия stackoverflow.com/questions/797127/… , за исключением того, что у этого есть exec, а у другого есть каналы.
Теги:

5 ответов

228
Лучший ответ

Exec

выполняет команду и никогда не возвращается. Это как оператор return в функции.

Если команда не найдена, exec возвращает false. Он никогда не возвращает true, потому что если команда найдена, она никогда не возвращается вообще. Также нет смысла возвращать STDOUT, STDERR или статус выхода команды. Вы можете найти документацию об этом в perlfunc, потому что это функция.

система

выполняет команду, а ваш Perl script продолжается после завершения команды.

Возвращаемое значение - это статус выхода команды. Вы можете найти документацию об этом в perlfunc.

обратные кавычки

как system выполняет команду, и ваш perl script продолжается после завершения команды.

В отличие от system возвращаемое значение STDOUT команды. qx// эквивалентен обратным отсчетам. Вы можете найти документацию об этом в perlop, потому что в отличие от system и exec это оператор.


Другие способы

То, что отсутствует в приведенном выше примере, - это способ выполнения команды асинхронно. Это означает, что ваш perl script и ваша команда запускаются одновременно. Это можно сделать с помощью open. Он позволяет читать STDOUT/STDERR и записывать в STDIN вашей команды. Это зависит от платформы.

Есть также несколько модулей, которые могут облегчить выполнение этих задач. Существует IPC::Open2 и IPC::Open3 и IPC::Run, а также Win32::Process::Create, если вы находитесь в окнах.

  • 1
    Я думаю, вы имеете в виду s / perlcunc / perlfunc / ... также документация perlipc подробно описывает открытие каналов.
  • 6
    perlcunc, возможно это будет мой новый ник ;-)
Показать ещё 1 комментарий
144

В общем, я использую system, open, IPC::Open2 или IPC::Open3 в зависимости от того, что я хочу делать. Оператор qx//, хотя и простой, слишком сдерживает свою функциональность, чтобы быть очень полезной вне быстрых хаков. Я нахожу open гораздо удобнее.

system: запустите команду и дождитесь ее возврата

Используйте system, если вы хотите запустить команду, не заботитесь о ее выходе и не хотите, чтобы Perl script ничего не делал, пока команда не закончится.

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

или

#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// или` `: запустите команду и запишите ее STDOUT

Используйте qx//, когда вы хотите запустить команду, захватить то, что она пишет в STDOUT, и не хотите, чтобы Perl script делал что-либо до тех пор, пока команда не завершится.

#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: замените текущий процесс другим процессом.

Используйте exec вместе с fork, когда вы хотите запустить команду, не заботятся о ее выходе, я хочу ждать, пока он вернется. system действительно просто

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
}

Вы также можете прочитать waitpid и perlipc.

open: запустите процесс и создайте канал для его STDIN или STDERR

Используйте open, когда вы хотите записать данные в процесс STDIN или прочитать данные из процесса STDOUT (но не оба одновременно).

#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: запустите процесс и создайте канал как для STDIN, так и для STDOUT

Используйте IPC::Open2, когда вам нужно читать и записывать в процесс STDIN и STDOUT.

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: запустите процесс и создайте канал для STDIN, STDOUT и STDERR

используйте IPC::Open3, когда вам нужно захватить все три стандартных дескриптора файла процесса. Я бы написал пример, но он работает в основном так же, как IPC:: Open2, но с немного другим порядком для аргументов и третьего дескриптора файла.

  • 0
    Очень информативный и актуальный ответ. Спасибо @ chas-owens
  • 0
    IPC :: Open3 слишком низкоуровневый для большинства применений. IPC :: Run3 и IPC :: Run обычно гораздо более уместны.
16

Позвольте мне сначала процитировать руководства:

perldoc exec():

Функция exec выполняет системную команду, а никогда не возвращает - использует систему вместо exec, если вы хотите, чтобы она вернула

perldoc system():

Точно так же, как exec LIST, за исключением того, что fork выполняется, и родительский процесс ожидает завершения дочернего процесса.

В отличие от exec и системы, backticks не дают вам возвращаемого значения, а собираемого STDOUT.

perldoc `String`:

Строка, которая (возможно) интерполирована и затем выполняется как системная команда с /bin/sh или ее эквивалентом. Символы, трубы и перенаправления Shell будут соблюдаться. Выбранный стандартный вывод команды возвращается; стандартная ошибка не изменяется.


Альтернативы:

В более сложных сценариях, где вы хотите получить STDOUT, STDERR или код возврата, вы можете использовать хорошо известные стандартные модули, такие как IPC:: Open2 и IPC:: Open3.

Пример:

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

Наконец, IPC::Run из CPAN также стоит посмотреть...

  • 3
    Это грубый ответ. Вы должны попытаться помочь без гнева.
  • 1
    Я думаю, что он просто делал ссылку на старый RTFM: P
Показать ещё 2 комментария
5

Какая разница между backticks Perl (`), system и exec?

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

exec

exec выполняет команду и никогда не возобновляет Perl script. Это для оператора script как a return для функции.

Если команда не найдена, exec возвращает false. Он никогда не возвращает true, потому что, если команда найдена, она никогда не возвращается вообще. Также нет смысла возвращать STDOUT, STDERR или статус выхода команды. Вы можете найти документацию об этом в perlfunc, потому что это функция.

Например:

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

В приведенном выше коде есть три оператора print, но из-за exec, оставляющего script, выполняется только первый оператор печати. Кроме того, команда exec не назначается какой-либо переменной.

Здесь вы получаете только результат первого оператора print и выполнения команды ls при стандартном выходе.

system

system выполняет команду, а ваш Perl script возобновляется после завершения команды. Возвращаемое значение - это статус выхода команды. Вы можете найти документацию об этом в perlfunc.

Например:

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

В приведенном выше коде есть три оператора print. По мере возобновления script после команды system выполняются все три оператора печати. ​​

Кроме того, результат выполнения system присваивается data2, но назначенное значение 0 (код выхода из ls).

Здесь вы получаете вывод первого оператора print, а затем команды ls, за которым следуют выходы последних двух операторов print на стандартном выходе.

backticks (`)

Подобно system, при выполнении команды в backticks выполняется эта команда, и ваш Perl script возобновляется после завершения команды. В отличие от system, возвращаемое значение STDOUT команды. qx// эквивалентен обратным выводам. Вы можете найти документацию об этом в perlop, потому что в отличие от системы и exec, это оператор.

Например:

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

В приведенном выше коде есть три оператора print, и все три выполняются. Вывод ls не собирается стандартизоваться напрямую, а назначается переменной data2, а затем печатается окончательным выражением печати. ​​

  • 0
    Лучшее объяснение с примером. Большое спасибо.
1

Разница между "exec" и "system" заключается в том, что exec заменяет вашу текущую программу "командой", а NEVER возвращается в вашу программу. система, с другой стороны, использует forks и запускает команду 'и возвращает вам статус выхода' command ', когда он выполняется. Задний тик запускает "команду", а затем возвращает строку, представляющую ее стандартную версию (независимо от того, что она напечатала на экране).

Вы также можете использовать popen для запуска команд оболочки, и я думаю, что есть оболочный модуль - "use shell", который дает вам прозрачный доступ к типичным командам оболочки.

Надеюсь, что это разъяснит вам.

  • 0
    Возможно, вы имеете в виду use Shell; ( search.cpan.org/dist/Shell/Shell.pm )? Я не думаю, что это широко распространено и не применимо к вопросу.
  • 1
    Последняя часть его вопроса была «есть ли другие способы запуска команд оболочки» - «Shell» - это еще один способ запуска команд оболочки.
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню