Почему эхо игнорирует символы моей кавычки?

24

Команда echoне включает полный текст, который я даю. Например, если я делаю:

   $ echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `    '

Это выводит:

echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk {print } `

Одиночные кавычки ( '), которые были в моей команде echo, не включены. Если я переключусь на двойные кавычки:

$ echo " echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `  "

echoвообще ничего не выводит! Почему он пропускает одинарные кавычки в первом примере и ничего не выводит во втором? Как мне заставить его выводить именно то, что я набрал?

Михаил Мрозек
источник
3
Не совсем уверен, что вы пытаетесь достичь здесь. Почему вы вкладываете одно эхо-выражение в другое? Или вы буквально пытаетесь распечатать команду (для примера или тому подобное)?
Энди Смит
Мне нужно вставить вывод эха в другой файл
Вы должны объяснить, что вы пытаетесь сделать. Например, «Я хочу добавить следующий текст:«… »в файл».
MikeyB
2
Я пытался редактировать это в течение 5 минут, но я серьезно не знаю, каков желаемый результат. Изменить : Хорошо, я думаю, у меня есть предположение сейчас, поэтому я попытался редактирование. Если это не то, что вы намеревались, дайте мне знать
Майкл Мрозек
1
@Michael - Wow - Если бы я мог дать вам несколько повторений для ваших правок, я бы - хорошая работа, сделав этот вопрос действительно замечательным!
Рэндалл

Ответы:

33

Ваша оболочка интерпретирует кавычки, 'и "прежде, чем они до них дойдут echo. Я обычно просто помещаю двойные кавычки вокруг моего аргумента, чтобы повторить, даже если они не нужны; например:

$ echo "Hello world"
Hello world

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

$ echo \'Hello world\'
'Hello world'

Или они уже должны использоваться внутри аргумента в кавычках (но это не может быть тот же тип цитаты, или вам все равно придется избегать его):

$ echo "'Hello world'"
'Hello world'

$ echo '"Hello world"'
"Hello world"

Во втором примере вы выполняете подстановку команд в середине строки:

grep  $ARG  /var/tmp/setfile  | awk {print $2}

Вещи, которые начинаются с $, также обрабатываются специально оболочкой - она ​​обрабатывает их как переменные и заменяет их значениями. Поскольку, скорее всего, ни одна из этих переменных не установлена ​​в вашей оболочке, она просто запускается

grep /var/tmp/setfile | awk {print}

Поскольку он grepвидит только один аргумент, он предполагает, что аргумент - это шаблон, который вы ищете, и что место, из которого он должен читать данные, - это stdin, поэтому он блокирует ожидание ввода. Вот почему ваша вторая команда, кажется, просто зависает.

Этого не произойдет, если вы заключите аргумент в одинарные кавычки (именно поэтому ваш первый пример почти сработал), так что это один из способов получить желаемый результат:

echo \'' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `    '\'

Вы также можете заключить его в двойные кавычки, но тогда вам нужно будет экранировать $s, чтобы оболочка не преобразовывала их как переменные, и обратные галочки, чтобы оболочка не запускала подстановку команд сразу:

echo "' echo PARAM=\`  grep  \$ARG  /var/tmp/setfile  | awk '{print \$2}' \`    '"
Михаил Мрозек
источник
7

Я не буду вдаваться в подробности того, почему ваши попытки ведут себя так, как они делают, потому что ответ Майкла Мрозека хорошо освещает это. В двух словах, все между одинарными кавычками ( '…') интерпретируется буквально (и, в частности, первый 'отмечает конец буквальной строки), тогда как `и $сохраняют свое особое значение между "…".

В одинарных кавычках нет кавычек, поэтому нельзя помещать одинарные кавычки в одинарные кавычки. Однако есть идиома, которая выглядит так:

echo 'foo'\''bar'

Это печатает foo'bar, потому что аргумент to echoсостоит из трехсимвольной строки в одинарных кавычках foo, объединенной с одним символом '(полученным путем защиты символа 'от его особого значения в предыдущем \), объединенной со строкой из трех символов в одинарных кавычках bar. Так что, хотя это не совсем то, что происходит за кулисами, вы можете представить '\''себе способ включения одинарных кавычек в строку в одинарных кавычках.

Если вы хотите напечатать сложные многострочные строки, лучшим инструментом является документ здесь . Здесь документ состоит из двух символов, <<за которыми следует маркер, например <<EOFнесколько строк текста, а затем маркер конца на одной строке. Если маркер заключен в кавычки каким-либо образом ( 'EOF'или "EOF"или \EOF«E», «OF» или…), то текст интерпретируется буквально (как внутри одинарных кавычек, за исключением того, что даже 'является обычным символом). Если маркер вообще не заключен в кавычки, то текст интерпретируется как строка в двойных кавычках, $\`сохраняя свой особый статус (но "и переводы строк интерпретируются буквально).

cat <<'EOF'
echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `
EOF
Жиль "ТАК - перестань быть злым"
источник
1

Хорошо, это будет работать:

echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '\''{print $2}'\'' `    '

Тестирование здесь: -

[asmith@yagi ~]$ echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '\''{print $2}'\'' `    '
 echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' ` 
Энди Смит
источник
0

Предложение Жиля об использовании документа здесь действительно хорошо, и даже работает в таких скриптовых языках, как Perl. В качестве конкретного примера, основанного на его ответе на вопрос ОП,

use strict;
my $cmd = q#cat <<'EOF' # . "\n" .
          q#echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `# . "\n" .
          q#EOF# ;
open (my $OUTPUT, "$cmd |");
print $_ while <$OUTPUT>;
close $OUTPUT;

Конечно, этот пример немного надуманный, но я нашел его полезным, скажем, для отправки операторов SQL psql(вместо cat).

(Обратите внимание, что любой не алфавитно-цифровой непробельный символ можно использовать вместо #приведенной выше общей конструкции цитирования, но хеш, похоже, хорошо выделяется для этого примера и не рассматривается как комментарий.)

Randall
источник
-1

Давайте возьмем вашу команду

$ echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print $2}' `    '

и сначала разбить его на слова, используя пробел без кавычек в качестве разделителя:

Arg[1]=“' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print”
Arg[2]=“$2}' `    '”

Далее мы делаем расширение параметров: расширяем, $…но не внутри '…'. Поскольку $2он пуст (если вы не установили его, например, через set -- …), он будет заменен пустой строкой.

Arg[1]=“' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '{print”
Arg[2]=“}' `    '”

Далее сделайте удаление цитаты.

Arg[1]=“ echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk {print”
Arg[2]=“} `    ”

Эти аргументы затем передаются в echo, который выводит их один за другим, разделенные одним пробелом.

“ echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk {print } `    ”

Я надеюсь, что эта пошаговая инструкция сделает наблюдаемое поведение более понятным. Чтобы избежать этой проблемы, избегайте одинарных кавычек:

$ echo ' echo PARAM=`  grep  $ARG  /var/tmp/setfile  | awk '\''{print $2}'\'' `    '

Это завершит строку в одинарных кавычках, затем добавит (экранированную) одинарную кавычку к слову, а затем начнет новую строку в одинарных кавычках, не разбивая слово на части.

MVG
источник