Чому відлуння ігнорує мої символи цитати?


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 - Нічого собі - Якби я міг дати тобі репліку для редагування, я б - приємна робота, зробивши це справді чудовим питанням!
Рандалл

Відповіді:


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, тому що аргумент до 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).

(Зауважте, що будь-який не буквено-цифровий символ #непробілу може бути використаний замість загальної конструкції цитування, наведеної вище, але, здається, хеш добре виділяється на цьому прикладі, і не розглядається як коментар.)


-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 PARAM=`  grep  $ARG  /var/tmp/setfile  | awk {print } `    ”

Я сподіваюся, що ця покрокова інструкція робить зрозумілу поведінку, що спостерігається. Щоб уникнути проблеми, уникайте таких цитат:

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

На цьому закінчиться одноцитуване рядок, потім додайте до слова (уникнуту) єдину цитату, а потім почніть новий рядок з одним цитуванням, і все не розбиваючи слово на частини.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.