У Bash, вказуючи аргументи командного рядка для команди, які символи потрібно уникнути?
Вони обмежуються метасимвол Баша: пробіл, табуляція
|, &, ;, (, ), <, і >?
У Bash, вказуючи аргументи командного рядка для команди, які символи потрібно уникнути?
Вони обмежуються метасимвол Баша: пробіл, табуляція
|, &, ;, (, ), <, і >?
Відповіді:
Наступні символи мають особливе значення для самої оболонки в деяких контекстах і, можливо, їх потрібно буде уникати в аргументах:
` Backtick (U + 0060 Grave Accent)~ Тільда (U + 007E)! Знак оклику (U + 0021)# Хеш ( цифра U + 0023)$ Знак долара (U + 0024)& Ampersand (U + 0026)* Зірочка (U + 002A)( Лівий парентез (U + 0028)) Права дужка (U + 0029) ( ⇥) Вкладка (U + 0009){ Лівий кронштейн (U + 007B Лівий фігурний кронштейн)[ Лівий квадратний кронштейн (U + 005B)| Вертикальна смуга (U + 007C вертикальна лінія)\ Backslash (U + 005C Зворотний Солідус); Крапка з комою (U + 003B)' Одиночна цитата / Апостроф (U + 0027)" Подвійна ціна (U + 0022)↩ Нова лінія (U + 000A)< Менше (U + 003C)> Більше, ніж (U + 003E)? Знак питання (U + 003F) Простір (U + 0020) 1Деякі з цих символів використовуються для більшої кількості речей і в інших місцях, ніж той, з яким я пов’язаний.
Є кілька кутових випадків, явно необов’язкових:
!можна відключити 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, ви в даний час у безпеці.
!тоді, коли включено розширення історії csh, як правило, не в сценаріях. [ ! -f a ]або find . ! -name...добре. Це підпадає під ваш чіткіший розділ обмежень, але, можливо, це варто чітко зазначити.
hash[foo"]"]=, ${var-foo"}"}, [[ "!" = b ]], [[ a = "]]" ]], регулярний вираз оператори [[ x =~ ".+[" ]]. Інші ключові слова , ніж {( if, while, for...) повинні бути вказані у такий спосіб , вони не визнаються в якості таких ...
]), тому я їх не перелічую. Я не думаю, що жодне ключове слово не потребує цитування у позиції аргументу.
У 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
Що стосується легкого вирішення проблеми в 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