Які символи потрібно уникати в аргументах командного рядка?


15

У Bash, вказуючи аргументи командного рядка для команди, які символи потрібно уникнути?

Вони обмежуються метасимвол Баша: пробіл, табуляція |, &, ;, (, ), <, і >?


Не забудьте (можливо) назву файлів глобулювання за допомогою * і?
Джефф Шаллер

Спасибі. Не могли б ви вичерпно перерахувати види символів, яких потрібно уникнути в аркушах cmd?
Тім

Список добре мати, але найголовніше, що потрібно розуміти при цитуванні, це: все між окремими цитатами передається буквально і без розбиття слів. Немає винятків. (Це означає, що немає способу вставити одну цитату в рамках однієї лапки, до речі, але це легко обійти .)
Wildcard

Відповіді:


22

Наступні символи мають особливе значення для самої оболонки в деяких контекстах і, можливо, їх потрібно буде уникати в аргументах:

Деякі з цих символів використовуються для більшої кількості речей і в інших місцях, ніж той, з яким я пов’язаний.


Є кілька кутових випадків, явно необов’язкових:

  • !можна відключити set +H, що є типовим для неінтерактивних оболонок.
  • {можна відключити set +B.
  • *і ?може бути відключена за допомогою set -fабоset -o noglob .
  • =Знак рівності (U + 003D) також потрібно уникати, якщо set -kабоset -o keyword увімкнено.

Уникнення нового рядка вимагає котирування - нахили в нижній частині риси не спрацюють. Будь-які інші символи, перелічені в IFS , потребуватимуть аналогічної обробки. Вам не потрібно бігти ]або }, але вам дійсно потрібно бігти , )тому що це оператор.

Деякі з цих персонажів мають більш жорсткі обмеження щодо того, коли їм справді потрібно втекти, ніж інші. Наприклад, a#bце нормально, але a #bце коментар, хоча >потребує втечі в обох контекстах. Не завадить уникнути їх усіх консервативно, і все простіше, ніж згадати про чіткі відмінності.

Якщо ім'я команди сама оболонка ключове слово ( if, for, do) , то вам потрібно бігти або процитувати його теж. Єдине цікаве з них - inце не очевидно, що це завжди ключове слово. Вам не потрібно робити це для ключових слів, що використовуються в аргументах, лише тоді, коли ви (безглуздо!) Назвали команду після одного з них. Операторам оболонок ( (, &тощо) завжди потрібно цитувати, де б вони не були.


1 Stéphane зазначив, що будь-який інший однобайтовий порожній символ з вашої мови також потребує втечі. У більшості поширених, розумних локалів, принаймні, на основі C або UTF-8, це лише символи пробілу, наведені вище. У деяких локальних ISO-8859-1 пробіл без перерви U + 00A0 вважається порожнім, включаючи Solaris, BSD та OS X (я думаю, що неправильно). Якщо ви маєте справу з довільним невідомим місцем, воно може включати майже все, включаючи букви, тож удача.

Можливо, один байт, який вважається порожнім, може з'являтися в багатобайтовому символі, який не був порожнім, і у вас не було б ніякого способу уникнути цього, крім того, щоб виставити все в лапки. Це не є теоретичним питанням: у локалі ISO-8859-1 зверху той A0байт, який вважається порожнім, може з'являтися в межах багатобайтових символів, таких як UTF-8, кодований "à" ( C3 A0). Щоб безпечно поводитися з цими символами, вам потрібно буде їх навести "à". Така поведінка залежить від конфігурації локалі в середовищі, де працює сценарій, а не в тому, де ви його написали.

Я думаю, що така поведінка порушена декількома способами, але ми повинні грати руку, з якою ми розбираємося. Якщо ви працюєте з будь-яким мультибайтовим набором символів, що не синхронізуються, найбезпечнішим було б процитувати все. Якщо ви перебуваєте в UTF-8 або C, ви в даний час у безпеці.


Інші пробіли у вашій місцевості також потребують втечі ( крім поточного багатобайтового через помилку )
Stéphane Chazelas

Вам потрібно уникати лише !тоді, коли включено розширення історії csh, як правило, не в сценаріях. [ ! -f a ]або find . ! -name...добре. Це підпадає під ваш чіткіший розділ обмежень, але, можливо, це варто чітко зазначити.
Стефан Шазелас

Зверніть увагу , що існують контексти , де інші символи повинні цитуючи як: hash[foo"]"]=, ${var-foo"}"}, [[ "!" = b ]], [[ a = "]]" ]], регулярний вираз оператори [[ x =~ ".+[" ]]. Інші ключові слова , ніж {( if, while, for...) повинні бути вказані у такий спосіб , вони не визнаються в якості таких ...
Stephane Chazelas

Наскільки це взагалі є аргументами командного рядка, інтерпретація залежить від розглянутої команди (так само ]), тому я їх не перелічую. Я не думаю, що жодне ключове слово не потребує цитування у позиції аргументу.
Майкл Гомер

2
Цитування вбудованих, тире чи% нічого не робить.
Майкл Гомер

3

У GNU Parallel це випробувано та широко використовується:

$a =~ s/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\'\202-\377]/\\$&/go;
# quote newline as '\n'                                                                                                         
$a =~ s/[\n]/'\n'/go;

Він випробуваний в bash, dash, ash, ksh, zsh, і fish. Деякі з символів не потребують цитування в деяких (версіях) оболонок, але вищевказане працює у всіх перевірених оболонках.

Якщо ви просто хочете цитувати рядок, ви можете передати його в parallel --shellquote:

printf "&*\t*!" | parallel --shellquote

Як я раніше не чув про паралель ...
Том H,

@TomH Будемо вдячні, якщо ви можете витратити 5 хвилин на роздуми про те, як ми могли до вас дійти.
Оле Танге

Я думаю, що це проблема прогресування. більшість людей не потребують і не розуміють паралельно, поки вони не прогресували через деякі етапи складності. На той час вони натрапили на xargs, nohup та подібні речі. Крім того, я не бачу багатьох людей, які паралельно вирішують проблеми в обміні стеками або коли я шукаю Google для вирішення проблем з баш
Tom H

1

Що стосується легкого вирішення проблеми в Perl, я дотримуюся принципу одинарних цитат. Баш-рядок в одинарних лапках може мати будь-який символ, крім самої однієї лапки.

Мій код:

my $bash_reserved_characters_re = qr([ !"#$&'()*;<>?\[\\`{|~\t\n]);

while(<>) {
    if (/$bash_reserved_characters_re/) {
        my $quoted = s/'/'"'"'/gr;
        print "'$quoted'";
    } else {
        print $_;
    }
}

Приклад виконання 1:

$ echo -n "abc" | perl escape_bash_special_chars.pl
abc

Приклад запуску 2:

echo "abc" | perl escape_bash_special_chars.pl
'abc
'

Приклад виконання 3:

echo -n 'ab^c' | perl escape_bash_special_chars.pl
ab^c

Приклад запуску 4:

echo -n 'ab~c' | perl escape_bash_special_chars.pl
'ab~c'

Приклад запуску 5:

echo -n "ab'c" | perl escape_bash_special_chars.pl
'ab'"'"'c'

echo 'ab'"'"'c'
ab'c

Так, дійсний пункт. На мою думку, більшість людей приземляться на цю сторінку, тому що вони мають вирішити проблему. Не тому, що це викликає цікаву академічну дискусію. Ось чому я хотів би запропонувати рішення та обговорити їх достоїнства, навіть будучи трохи поза темою.
Ярі Туркія

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