обратные кавычки perl: используйте bash вместо sh

Я заметил, что когда я использую обратные кавычки в perl, команды выполняются с использованием sh, а не bash, что вызывает у меня некоторые проблемы.

Как я могу изменить это поведение, чтобы Perl использовал bash?

PS. Я пытаюсь запустить следующую команду:

paste filename <(cut -d \" \" -f 2 filename2 | grep -v mean) >> filename3

person David B    schedule 30.07.2010    source источник
comment
Я почти уверен, что нет.   -  person tster    schedule 30.07.2010
comment
Зачем? Какое ваше преуменьшение?   -  person David B    schedule 30.07.2010
comment
sh универсален, bash - нет.   -  person Amadan    schedule 30.07.2010
comment
@ether: попробуйте perl -wle'print `echo foo; ps --forest`', чтобы увидеть sh.   -  person Amadan    schedule 30.07.2010
comment
Кстати, я пытаюсь запустить следующую команду: paste filename <(cut -d \" \" -f 2 filename2 | grep -v mean) >> filename3   -  person David B    schedule 30.07.2010
comment
Почему ты вообще обстреливаешься? Вы можете делать все, что хотите, в чистом виде. Если вы хотите запускать что-то в оболочке, используйте сценарий оболочки.   -  person Daenyth    schedule 30.07.2010


Ответы (6)


Пытаться

`bash -c \"your command with args\"`

Я почти уверен, что аргумент -c интерпретируется так, как bash интерпретирует свою командную строку. Хитрость в том, чтобы защитить его от sh - вот для чего нужны кавычки.

person Community    schedule 30.07.2010
comment
Теперь я получаю ошибки типа -f 1 / tmp / file | grep -v mean) ›› / tmp / file2: -c: line 0: неожиданный EOF при поиске соответствия `) '-f 1 / tmp / file3 | grep -v mean) ›› / tmp / file4: -c: строка 1: синтаксическая ошибка: неожиданный конец файла - person David B; 30.07.2010
comment
Может быть \ не нужны в моем примере. Кроме того, не используйте внутри своей команды - используйте '. - person ; 30.07.2010
comment
РЕШЕНО! Единственное, что у меня сработало, это: `bash -c 'my_command'` - person David B; 30.07.2010
comment
Вы также можете избежать проблем с цитированием, используя open my $fh, '-|', qw(bash -c), $cmdline, который почти гарантированно работает точно так же, как `$ cmdline`, но интерфейс другой. - person hobbs; 01.08.2010
comment
Эти \ бесполезны, и имело бы гораздо больше смысла использовать одинарные кавычки, чем двойные. - person ikegami; 04.08.2017
comment
@ikegami Конечно, можно использовать одинарные кавычки, и было бы лучше. Но что, если они уже используются внутри your command with args? Что, если пользователю нужна интерполяция внутри -c аргумента? - person ; 04.08.2017
comment
@Arkadiy, Re Но что, если они уже используются внутри. Вся суть использования одинарных кавычек заключается в том, что у вас меньше для экранирования и что они предотвращают случайную интерполяцию, поэтому указание на то, что вам нужно избегать одинарных кавычек (''\''), неискренне. - person ikegami; 04.08.2017
comment
@Arkadiy, Re Что делать, если пользователю нужна интерполяция внутри аргумента -c?, это было бы очень плохо. Использование одинарных кавычек фактически исключает возможность совершить эту ошибку! Например, все три из bash -c "cat -- $file", bash -c "cat -- \"$file\"" и bash -c "cat -- '$file'" содержат ошибки. Вы должны использовать bash -c 'cat -- "$0"' "$file" или FILE="$file" bash -c 'cat -- "$FILE"' - person ikegami; 04.08.2017

«Системная оболочка» обычно неизменяема. См. perldoc -f exec:

Если в LIST более одного аргумента или если LIST является массивом с более чем одним значением, вызывает execvp (3) с аргументами в LIST. Если есть только один скалярный аргумент или массив с одним элементом в нем, аргумент проверяется на наличие метасимволов оболочки, и если они есть, весь аргумент передается в командную оболочку системы для анализа (это "/ bin / sh -c "на платформах Unix, но может отличаться на других платформах).

Если вам действительно нужен bash для выполнения определенной задачи, рассмотрите возможность его явного вызова:

my $result = `/usr/bin/bash command arguments`;

или даже:

open my $bash_handle, '| /usr/bin/bash' or die "Cannot open bash: $!";
print $bash_handle 'command arguments';

Вы также можете поместить свои команды bash в файл .sh и вызывать его напрямую:

my $result = `/usr/bin/bash script.pl`;
person Ether    schedule 30.07.2010
comment
Я все еще не могу добиться ожидаемого поведения. Причина, по которой я хотел bash, заключается в том, что я запускаю команду ac, используя ‹(grep ...), и кажется, что sh ее не поддерживает (но bash поддерживает). Если я запускаю свою команду как пользователь, прямо из bash она работает нормально. Если я запускаю его из perl в обратных кавычках, то кричит sh: Синтаксическая ошибка: (неожиданно, если я запускаю его в обратных кавычках, которым предшествует / usr / bin / bash, я все равно получаю то же самое от sh. - person David B; 30.07.2010
comment
@ Дэвид: Я не совсем понимаю, какую команду вы пытаетесь запустить; Можете ли вы отредактировать это в своем вопросе с форматированием кода? - person Ether; 30.07.2010

Этот пример работает для меня:

$ perl -e 'print `/bin/bash -c "echo <(pwd)"`'
/dev/fd/63
person Dennis Williamson    schedule 30.07.2010

Лучшее решение для работы с запущенным bash и вложенными кавычками - это статья: Как использовать синтаксис bash в системе Perl ()?

my @args = ( "bash", "-c", "diff <(ls -l) <(ls -al)" );
system(@args);
person joseph    schedule 09.12.2014

Я думал, что perl будет учитывать переменную $SHELL, но потом мне пришло в голову, что ее поведение может фактически зависеть от реализации exec вашей системы. По-моему, кажется, что exec

выполнит оболочку (/ bin / sh) с путем к файлу в качестве первого аргумента.

Вы всегда можете сделать qw/bash your-command/, не так ли?

person Pedro Silva    schedule 30.07.2010
comment
Я все еще получаю sh: Синтаксическая ошибка: (неожиданно. См. Комментарий к исходному сообщению для команды, которую я пытаюсь запустить. - person David B; 30.07.2010

Создайте подпрограмму perl:

sub bash { return `cat << 'EOF' | /bin/bash\n$_[0]\nEOF\n`; }

И используйте его, как показано ниже:

my $bash_cmd = 'paste filename <(cut -d " " -f 2 filename2 | grep -v mean) >> filename3';
print &bash($bash_cmd);

Или используйте perl here-doc для многострочных команд:

$bash_cmd = <<'EOF';
    for (( i = 0; i < 10; i++ )); do
       echo "${i}"
    done
EOF
print &bash($bash_cmd);
person bruce    schedule 05.09.2013