Di Bash, saat menentukan argumen baris perintah ke perintah, karakter apa yang diperlukan untuk melarikan diri?
Apakah mereka terbatas pada metakarakter dari Bash: ruang, tab,
|
, &
, ;
, (
, )
, <
, dan >
?
Di Bash, saat menentukan argumen baris perintah ke perintah, karakter apa yang diperlukan untuk melarikan diri?
Apakah mereka terbatas pada metakarakter dari Bash: ruang, tab,
|
, &
, ;
, (
, )
, <
, dan >
?
Jawaban:
Karakter berikut memiliki arti khusus untuk shell itu sendiri dalam beberapa konteks dan mungkin perlu diloloskan dalam argumen:
`
Backtick (Aksen Kuburan U + 0060)~
Tilde (U + 007E)!
Tanda seru (U + 0021)#
Hash (Tanda Nomor U + 0023)$
Tanda dolar (U + 0024)&
Ampersand (U + 0026)*
Asterisk (U + 002A)(
Parenthesis Kiri (U + 0028))
Tanda kurung kanan (U + 0029)
( ⇥
) Tab (U + 0009){
Brace kiri (Braket Keriting Kiri + 007B)[
Braket persegi kiri (U + 005B)|
Bilah vertikal (U + 007C Garis Vertikal)\
Backslash (U + 005C Reverse Solidus);
Titik koma (U + 003B)'
Kutipan tunggal / Apostrof (U + 0027)"
Kutipan ganda (U + 0022)↩
Baris baru (U + 000A)<
Kurang dari (U + 003C)>
Lebih besar dari (U + 003E)?
Tanda tanya (U + 003F)
Spasi (U + 0020) 1Beberapa karakter tersebut digunakan untuk lebih banyak hal dan di lebih banyak tempat daripada yang saya tautkan.
Ada beberapa kasus sudut yang secara eksplisit opsional:
!
dapat dinonaktifkan dengan set +H
, yang merupakan default di shell non-interaktif.{
dapat dinonaktifkan dengan set +B
.*
dan ?
dapat dinonaktifkan dengan set -f
atauset -o noglob
.=
Equals tanda (U + 003D) juga perlu melarikan diri jika set -k
atauset -o keyword
diaktifkan.Melarikan diri dari baris baru memerlukan penawaran - garis miring terbalik tidak akan berfungsi. Setiap karakter lain yang terdaftar di IFS akan membutuhkan penanganan yang sama. Anda tidak perlu untuk melarikan diri ]
atau }
, tetapi Anda tidak perlu untuk melarikan diri )
karena operator.
Beberapa dari karakter ini memiliki batasan ketat ketika mereka benar-benar perlu melarikan diri daripada yang lain. Misalnya, a#b
tidak apa-apa, tetapi a #b
merupakan komentar, sementara >
akan perlu melarikan diri dalam kedua konteks. Tidak ada ruginya untuk melarikan diri dari mereka semua secara konservatif, dan lebih mudah daripada mengingat perbedaan-perbedaan yang baik.
Jika nama perintah Anda sendiri adalah kata kunci shell ( if
, for
, do
) maka Anda akan perlu untuk melarikan diri atau mengutip juga. Satu-satunya yang menarik adalah in
, karena tidak jelas bahwa itu selalu kata kunci. Anda tidak perlu melakukan itu untuk kata kunci yang digunakan dalam argumen, hanya ketika Anda (bodoh!) Bernama perintah setelah salah satu dari mereka. Operator Shell ( (
,, &
dll) selalu perlu mengutip di mana pun mereka berada.
1 Stéphane telah mencatat bahwa karakter kosong byte tunggal lainnya dari lokal Anda juga perlu melarikan diri. Secara umum, lokal yang masuk akal, setidaknya yang didasarkan pada C atau UTF-8, itu hanya karakter spasi putih di atas. Di beberapa tempat ISO-8859-1, ruang tanpa-istirahat U + 00A0 dianggap kosong, termasuk Solaris, BSDs, dan OS X (saya kira salah). Jika Anda berurusan dengan lokal yang tidak dikenal yang sewenang-wenang, itu bisa mencakup apa saja, termasuk surat, semoga sukses.
Dapat dibayangkan, satu byte yang dianggap kosong dapat muncul dalam karakter multi-byte yang tidak kosong, dan Anda tidak akan bisa menghindarinya selain meletakkan semuanya dalam tanda kutip. Ini bukan masalah teoretis: di lokal ISO-8859-1 dari atas, A0
byte yang dianggap kosong dapat muncul dalam karakter multibyte seperti UTF-8 yang dikodekan "à" ( C3 A0
). Untuk menangani karakter-karakter itu dengan aman, Anda perlu mengutipnya "à"
. Perilaku ini tergantung pada konfigurasi lokal di lingkungan yang menjalankan skrip, bukan yang Anda gunakan.
Saya pikir perilaku ini rusak beberapa cara, tetapi kita harus bermain tangan kita ditangani. Jika Anda bekerja dengan rangkaian karakter multibyte yang tidak dapat disinkronkan sendiri, hal paling aman adalah mengutip semuanya. Jika Anda menggunakan UTF-8 atau C, Anda aman (untuk saat ini).
!
ketika ekspansi sejarah csh diaktifkan, biasanya tidak dalam skrip. [ ! -f a ]
atau find . ! -name...
baik-baik saja. Itu dicakup oleh bagian batas ketat Anda, tetapi mungkin perlu disebutkan secara eksplisit.
hash[foo"]"]=
, ${var-foo"}"}
, [[ "!" = b ]]
, [[ a = "]]" ]]
, operator regexp untuk [[ x =~ ".+[" ]]
. Kata kunci selain {
( if
, while
, for
...) akan perlu dikutip sehingga mereka tidak diakui seperti itu ...
]
), jadi saya tidak mencantumkannya. Saya rasa kata kunci apa pun tidak perlu dikutip dalam posisi argumen.
Dalam GNU Paralel ini diuji dan digunakan secara luas:
$a =~ s/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\'\202-\377]/\\$&/go;
# quote newline as '\n'
$a =~ s/[\n]/'\n'/go;
Hal ini diuji dalam bash
, dash
, ash
, ksh
, zsh
, dan fish
. Beberapa karakter tidak perlu mengutip dalam beberapa (versi) dari shell, tetapi di atas berfungsi di semua shell yang diuji.
Jika Anda hanya ingin string dikutip, Anda dapat pipa ke parallel --shellquote
:
printf "&*\t*!" | parallel --shellquote
Untuk solusi pelarian ringan di Perl, saya mengikuti prinsip tanda kutip tunggal. Bash-string dalam tanda kutip tunggal dapat memiliki karakter apa pun, kecuali tanda kutip tunggal itu sendiri.
Kode saya:
my $bash_reserved_characters_re = qr([ !"#$&'()*;<>?\[\\`{|~\t\n]);
while(<>) {
if (/$bash_reserved_characters_re/) {
my $quoted = s/'/'"'"'/gr;
print "'$quoted'";
} else {
print $_;
}
}
Contoh jalankan 1:
$ echo -n "abc" | perl escape_bash_special_chars.pl
abc
Contoh menjalankan 2:
echo "abc" | perl escape_bash_special_chars.pl
'abc
'
Contoh jalankan 3:
echo -n 'ab^c' | perl escape_bash_special_chars.pl
ab^c
Contoh jalankan 4:
echo -n 'ab~c' | perl escape_bash_special_chars.pl
'ab~c'
Contoh jalankan 5:
echo -n "ab'c" | perl escape_bash_special_chars.pl
'ab'"'"'c'
echo 'ab'"'"'c'
ab'c