У 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