Как я могу избежать двойных кавычек в системной команде в этом perl oneliner?

Для моего назидания я хотел бы узнать, как избежать кавычек в команде system в следующем perl oneliner:

$ ls -p | grep -v / | perl -lane 'system("echo \"$_\"");'

без использования escape-последовательности \", как показано здесь: https://stackoverflow.com/a/1250279/3367247

(Очевидно, что эта команда не делает ничего полезного; она просто печатает имена файлов, в которых есть пробелы. Но она служит для краткого объяснения моей проблемы.)

Я попробовал следующее (извините за изображения, но мне показалось, что проще всего расшифровать цитату):

  1. системная команда с двойными кавычками: system("echo "$_"") введите здесь описание изображения

Код: $ ls -p | grep -v / | perl -lane 'system("echo ''"''$_''"''");'

  1. системная команда с одинарными кавычками: system('echo "$_"') введите здесь описание изображения

Код: $ ls -p | grep -v / | perl -lane 'system('"'"'echo "$_"'"'"');'

Ни один из них не работает. Есть ли способ сделать это в виде связанного ответа?

EDIT: мне нужны двойные кавычки вокруг $_ в команде echo, потому что строка в $_ содержит круглые скобки, а не потому, что она содержит пробелы, как я изначально думал.


person dqbydt    schedule 27.03.2019    source источник
comment
Вам также следует рассмотреть возможность передачи системе списка аргументов. Таким образом, вам не нужно вызывать оболочку, и цитирование больше не является проблемой: system('/bin/echo', $_) -- perldoc.perl.org/functions/system.html   -  person glenn jackman    schedule 28.03.2019
comment
Спасибо, @Shawn, я думаю, мой вопрос больше о понимании синтаксиса bash, чем о поиске лучшего решения Perl (хотя, конечно, новые знания Perl всегда приветствуются). Я думал, что понял, как работает одинарное/двойное цитирование после прочтения связанного ответа, но в данном случае это не удалось.   -  person dqbydt    schedule 28.03.2019
comment
@glennjackman Я не знал, что ты можешь позвонить system со списком, спасибо.   -  person dqbydt    schedule 28.03.2019
comment
@dqbydt В первом примере вам нужно вставить обратную косую черту перед кавычками: ... | perl -lane 'system("echo ''\"''$_''\"''")' (сравните с исходным примером, обратная косая черта не является частью синтаксиса оболочки, а является частью строки аргумента perl, переданной system)   -  person Håkon Hægland    schedule 28.03.2019
comment
Для второго примера: вы не можете использовать одинарные кавычки, поскольку $_ является переменной perl и требует интерполяции двойных кавычек в строку.   -  person Håkon Hægland    schedule 28.03.2019


Ответы (2)


Я хотел бы узнать, как избежать кавычек внутри системной команды в следующем perl oneliner:

$ ls -p | grep -v / | perl -lane 'system("echo \"$_\"");'

без использования управляющей последовательности \", как показано здесь: [...]

Эти примеры предназначены для экранирования одинарных кавычек, в вашем примере используются двойные кавычки \"$_\". В Bash все в одинарных кавычках воспринимается буквально (кроме самой одинарной кавычки), то же самое не верно для двойных кавычек. Например, $ в двойных кавычках не является литералом $, а указывает на то, что последует расширение переменной.

Теперь в вашем распоряжении три уровня интерпретации котировок.

  • Сначала внешняя оболочка (командная строка):

    perl -lane 'system("echo \"$_\"");'
    
  • Затем интерпретатор perl:

    system("echo \"$_\");
    
  • Затем вторая оболочка (здесь используется Bash):

    echo "xxx"
    

где xxx — расширение $_ в сценарии perl

Ваша команда не содержит внутренних одинарных кавычек, поэтому нет необходимости использовать конструкции кавычек Bash для экранирования одинарных кавычек, например

It's fine  -> 'It'"'"'s fine'

or

It's fine  -> 'It'\''s fine'

Кроме того, вам нужно избежать двойной кавычки в скрипте perl.

system("echo \"$_\"")

поскольку они находятся внутри двойных кавычек, в качестве альтернативы вы можете удалить их, так как echo здесь не нужны двойные кавычки:

system("echo $_")

будет работать нормально, или вы можете сделать, как предложено в комментариях:

system(qq/echo "$_"/)

или используйте СПИСОК формы system с более чем одним аргументом

system("/bin/echo", $_)

Однако, если вы хотите использовать одинарные кавычки, например:

system('echo ' . $_)

вам нужно будет вызвать экранирование одиночной кавычки оболочки:

'system('"'"'echo ''"' . $_)'

или (используя двойные кавычки):

"system('echo ' . "'$'"_)"
person Håkon Hægland    schedule 28.03.2019
comment
Оказывается, мне нужны двойные кавычки в команде echo, но не потому, что строка perl содержит пробелы, как я изначально думал. Это потому, что он содержит круглые скобки. Поэтому форму системы с одинарными кавычками необходимо изменить на system('echo "' . $_ . '"'). И escape-последовательность оболочки с одинарными кавычками, чтобы приспособиться к этому, становится довольно умопомрачительной, лол. - person dqbydt; 28.03.2019

Я хотел бы опубликовать некоторые идеи, которые я почерпнул из полезных комментариев и принятого ответа (спасибо всем!). В исходной команде, которую я представил: $ ls -p | grep -v / | perl -lane 'system("echo \"$_\"");' есть два интерпретатора: bash и perl, вступающие в игру:

  1. Первоначальная команда, интерпретируемая bash, ничего не затрагивает в (единственной паре) одинарных кавычек (т. е. всего, что после -lane) и передает ее в перл в виде скрипта.

  2. Затем интерпретатор Perl обрабатывает этот сценарий, состоящий из одной команды system. Именно интерпретатор perl отвечает за создание окончательной командной строки echo, которая возвращается обратно в bash для интерпретации. Эта последняя команда bash должна быть динамически сгенерирована из $_. Есть два способа сделать это:

    (a) Используйте системную команду с двойными кавычками, чтобы $_ интерполировалось [т.е. system("echo $_")] Но обратите внимание, отображаемая строка должна быть окружена ", потому что она может содержать круглые скобки. Итак, нам нужно, чтобы perl выдал в этой последней командной строке bash литерал "s вокруг $_ (который будет расширен за счет внешних "s перед отправкой стучать). Теперь есть два способа сделать это это:

    (a-i) Экранируйте ", используя \, чтобы вывести буквальные кавычки: "echo \"$_\""

    (a-ii) Используйте оператор qq, который понижает особый статус, присвоенный "s в строке Perl, и который затем может использоваться как обычные символы: qq(echo "$_").

    (b) - ИЛИ - другой способ создания окончательной команды bash - использовать одинарные кавычки в команде system, как это было предложено @Håkon в его ответе: system('echo ' . $_). Но нам по-прежнему нужны кавычки вокруг $_, как обсуждалось ранее, поэтому нам нужно изменить это на: system('echo "' . $_ . '"'). Теперь задача сводится к выяснению экранирования в одинарных кавычках bash, чтобы убедиться, что Perl увидит эту строку.

Окончательные формы команды perl:

2-a-i: perl -lane 'system("echo \"$_\"");'

2-a-ii: perl -lane 'system(qq/echo "$_"/);'

И наконец:

2-b: perl -lane 'system('"'"'echo "'"'"'.$_.'"'"'"'"'"');'

Это извращение 's и "s - это то, чего я намеревался достичь, так что МИССИЯ ВЫПОЛНЕНА! :D

Примечание редактора: с практической, удобной точки зрения, форма qq кажется наиболее удобной для простой вставки окончательной желаемой команды bash в вызов perl system (и тогда вы можете просто заменить имена файлов на $_).

person dqbydt    schedule 28.03.2019