Hanya catatan tambahan di atas jawaban baik @ Kusalananda .
echo run after_bundle
baik-baik saja karena tidak ada karakter dalam 3 argumen¹ yang dilewatkan untuk echo
mengandung karakter yang khusus untuk shell.
Dan (poin tambahan yang ingin saya buat di sini) tidak ada sistem lokal di mana byte tersebut dapat diterjemahkan ke karakter yang khusus untuk shell.
Semua karakter itu dalam apa yang POSIX sebut sebagai set karakter portabel . Karakter-karakter tersebut harus ada dan dikodekan sama di semua set karakter pada sistem POSIX².
Sehingga baris perintah akan diinterpretasikan sama terlepas dari lokalnya.
Sekarang, jika kita mulai menggunakan karakter di luar set karakter portabel, itu adalah ide yang baik untuk mengutip mereka bahkan jika mereka tidak khusus untuk shell, karena di lokal lain, byte yang membentuknya dapat ditafsirkan sebagai karakter berbeda yang dapat menjadi khusus untuk shell. Perhatikan bahwa apakah Anda menggunakan echo
atau perintah lain, masalahnya bukan pada echo
tetapi dengan bagaimana shell mengurai kodenya.
Misalnya dalam UTF-8:
echo voilà | iconv -f UTF-8 -t //TRANSLIT
Itu à
dikodekan sebagai 0xc3 0xa0. Sekarang, jika Anda memiliki baris kode dalam skrip shell dan skrip shell dipanggil oleh pengguna yang menggunakan lokal yang charsetnya bukan UTF-8, dua byte itu bisa membuat karakter yang sangat berbeda.
Misalnya, dalam fr_FR.ISO8859-15
lokal, lokal Prancis tipikal menggunakan charset byte tunggal standar yang mencakup bahasa Prancis (yang sama digunakan untuk sebagian besar bahasa Eropa barat termasuk bahasa Inggris), bahwa byte 0xc3 ditafsirkan sebagai Ã
karakter dan 0xa0 sebagai non- melanggar karakter ruang.
Dan pada beberapa sistem seperti NetBSD³, bahwa ruang tanpa putus dianggap sebagai karakter kosong ( isblank()
di atasnya mengembalikan true, itu cocok dengan [[:blank:]]
) dan kerang seperti bash
karenanya memperlakukannya sebagai pembatas token dalam sintaks mereka.
Itu berarti bahwa alih-alih menjalankan echo
dengan $'voil\xc3\xa0'
sebagai argumen, mereka menjalankannya dengan $'voil\xc3'
sebagai argumen, yang berarti tidak akan mencetak voilà
dengan benar.
Ia mendapat lebih buruk dengan set karakter Cina seperti BIG5, BIG5-HKSCS, GB18030, GBK yang memiliki banyak karakter yang encoding berisi encoding sama dengan |
, `
, \
(untuk nama yang terburuk) (juga bahwa SJIS menggelikan, alias Microsoft Kanji, kecuali bahwa itu ¥
bukan \
, tapi masih diperlakukan \
oleh sebagian besar alat karena dikodekan sebagai 0x5c di sana).
Misalnya, jika di zh_CN.gb18030
lokal Cina, Anda menulis skrip seperti:
echo 詜 reboot
Skrip itu akan menampilkan 詜 reboot
dalam lokal menggunakan GB18030 atau GBK, 唰 reboot
di lokal menggunakan BIG5 atau BIG5-HKSCS, tetapi di lokal C menggunakan ASCII atau lokal menggunakan ISO8859-15 atau UTF-8, akan menyebabkan reboot
dijalankan karena pengkodean GB18030 dari 詜
adalah 0xd4 0x7c dan 0x7c adalah pengkodean |
dalam ASCII sehingga kami akhirnya menjalankan:
echo �| reboot
(yang mewakili byte 0xd4 diberikan di lokal). Contoh menggunakan yang kurang berbahaya uname
alih-alih reboot
:
$ echo $'echo \u8a5c uname' | iconv -t gb18030 > myscript
$ LC_ALL=zh_CN.gb18030 bash ./myscript | sed -n l
\324| uname$
$ LC_ALL=C bash ./myscript | sed -n l
Linux$
( uname
Dijalankan).
Jadi saran saya adalah mengutip semua string yang berisi karakter di luar set karakter portabel.
Namun perhatikan bahwa karena penyandian \
dan `
ditemukan dalam penyandian beberapa karakter tersebut, lebih baik untuk tidak menggunakan \
atau "..."
atau $'...'
(di dalamnya mana `
dan / atau \
masih istimewa), tetapi '...'
alih - alih mengutip karakter di luar rangkaian karakter portabel.
Saya tidak mengetahui adanya sistem yang memiliki lokal di mana charset memiliki karakter apa pun (selain '
tentu saja itu sendiri) yang penyandiannya berisi penyandian '
, jadi itu '...'
pasti yang paling aman.
Perhatikan bahwa beberapa shell juga mendukung $'\uXXXX'
notasi untuk mengekspresikan karakter berdasarkan titik kode Unicode mereka. Dalam cangkang suka zsh
dan bash
, karakter dimasukkan disandikan dalam charset lokal (meskipun dapat menyebabkan perilaku yang tidak terduga jika charset itu tidak memiliki karakter itu). Itu memungkinkan Anda menghindari memasukkan karakter non-ASCII dalam kode shell Anda.
Di atas:
echo 'voilà' | iconv -f UTF-8 -t //TRANSLIT
echo '詜 reboot'
Atau:
echo $'voil\u00e0'
echo $'\u8a5c reboot'
(dengan peringatan itu bisa mematahkan skrip ketika dijalankan di lokal yang tidak memiliki karakter tersebut).
Atau lebih baik, karena \
juga khusus untuk echo
(atau setidaknya beberapa echo
implementasi, setidaknya yang sesuai Unix):
printf '%s\n' 'voilà' | iconv -f UTF-8 -t //TRANSLIT
printf '%s\n' '詜 reboot'
(catatan yang \
juga khusus dalam argumen pertama printf
, jadi karakter non-ASCII juga lebih baik dihindari di sana jika mereka mungkin mengandung pengkodean \
).
Perhatikan bahwa Anda juga bisa melakukan:
'echo' 'voilà' | 'iconv' '-f' 'UTF-8' '-t' '//TRANSLIT'
(Itu akan berlebihan tetapi bisa memberi Anda ketenangan pikiran jika Anda tidak yakin karakter mana yang ada di set karakter portabel)
Juga pastikan untuk tidak pernah menggunakan `...`
bentuk substitusi perintah kuno (yang memperkenalkan pemrosesan backslash tingkat lain), tetapi gunakan $(...)
sebagai gantinya.
¹ teknis, echo
juga diberikan sebagai argumen ke echo
utilitas (untuk menceritakannya bagaimana itu dipanggil), itu argv[0]
dan argc
adalah 3, meskipun dalam kebanyakan kerang saat ini echo
adalah builtin, sehingga exec()
dari /bin/echo
file dengan daftar 3 argumen disimulasikan oleh kulit. Juga umum untuk mempertimbangkan daftar argumen sebagai mulai dengan yang kedua ( argv[1]
untuk argv[argc - 1]
) karena itulah yang sebagian besar ditindaklanjuti oleh perintah.
² pengecualian untuk yang menjadi menggelikan ja_JP.SJIS
lokal sistem FreeBSD yang charset tidak memiliki \
atau ~
karakter!
³ perhatikan bahwa walaupun banyak sistem (FreeBSD, Solaris, bukan yang GNU) menganggap U + 00A0 sebagai [[:blank:]]
di dalam UTF-8 lokal, sedikit yang dilakukan di lokal lain seperti yang menggunakan ISO8859-15, mungkin untuk menghindari masalah seperti ini.