Solo una nota in aggiunta alla bella risposta di @ Kusalananda .
echo run after_bundle
va bene perché nessuno dei caratteri in questi 3 argomenti¹ è passato a echo
contenere caratteri speciali per la shell.
E (il punto in più che voglio sottolineare qui) non esiste alcuna locale di sistema in cui quei byte possano essere tradotti in caratteri speciali della shell.
Tutti quei personaggi sono in ciò che POSIX chiama il set di caratteri portatile . Questi caratteri dovrebbero essere presenti e codificati allo stesso modo in tutti i set di caratteri su un sistema POSIX².
In tal modo la riga di comando verrà interpretata allo stesso modo indipendentemente dalla locale.
Ora, se iniziamo a usare caratteri al di fuori di quel set di caratteri portatile, è una buona idea citarli anche se non sono speciali per la shell, perché in un'altra locale, i byte che li costituiscono possono essere interpretati come caratteri diversi che potrebbero diventare speciale per la shell. Nota che è se stai usando echo
o qualsiasi altro comando, il problema non è con echo
ma con come la shell analizza il suo codice.
Ad esempio in un UTF-8:
echo voilà | iconv -f UTF-8 -t //TRANSLIT
Questo à
è codificato come 0xc3 0xa0. Ora, se hai quella riga di codice in uno script di shell e lo script di shell viene invocato da un utente che utilizza una locale il cui set di caratteri non è UTF-8, quei due byte potrebbero creare caratteri molto diversi.
Ad esempio, in una fr_FR.ISO8859-15
locale, una tipica locale francese che utilizza il set di caratteri a byte singolo standard che copre la lingua francese (la stessa utilizzata per la maggior parte delle lingue dell'Europa occidentale incluso l'inglese), che 0xc3 byte viene interpretato come Ã
carattere e 0xa0 come non- carattere spazio di rottura.
E su alcuni sistemi come NetBSD³, quello spazio non-break viene considerato come un carattere vuoto ( isblank()
su esso ritorna vero, è abbinato da [[:blank:]]
) e shell come bash
quindi lo trattano come un delimitatore di token nella loro sintassi.
Ciò significa che invece di funzionare echo
con $'voil\xc3\xa0'
come argomento, lo eseguono $'voil\xc3'
come argomento, il che significa che non verrà stampato voilà
correttamente.
Si ottiene molto peggio con i set di caratteri cinesi come BIG5, BIG5-HKSCS, GB18030, GBK che hanno molti personaggi le cui codifica contiene la stessa codifica come |
, `
, \
(per citare il peggiore) (anche che SJIS ridicola, aka Microsoft Kanji, ad eccezione che è ¥
invece di \
, ma è ancora trattato \
dalla maggior parte degli strumenti in quanto è codificato come 0x5c lì).
Ad esempio, se in una lingua zh_CN.gb18030
cinese, scrivi uno script come:
echo 詜 reboot
Lo script verrà generato 詜 reboot
in una locale usando GB18030 o GBK, 唰 reboot
in una locale usando BIG5 o BIG5-HKSCS, ma in una locale C usando ASCII o una locale usando ISO8859-15 o UTF-8, verrà reboot
eseguito perché la codifica GB18030 di 詜
è 0xd4 0x7c e 0x7c è la codifica di |
in ASCII quindi finiamo per eseguire:
echo �| reboot
(che rappresenta comunque il byte 0xd4 è reso nella locale). Esempio usando il meno dannoso uname
invece di 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
stato eseguito).
Quindi il mio consiglio sarebbe di citare tutte le stringhe che contengono caratteri al di fuori del set di caratteri portatile.
Tuttavia notare che, poiché la codifica dei \
e `
si trovano nella codifica di alcuni di questi personaggi, non è meglio usare \
o "..."
o $'...'
(al cui interno `
e / o \
sono ancora speciale), ma il '...'
posto per citare personaggi al di fuori del set di caratteri portatile.
Non sono a conoscenza di alcun sistema che abbia una localizzazione in cui il set di caratteri ha un carattere (diverso da '
se stesso ovviamente) la cui codifica contiene la codifica di '
, quindi quelli '...'
dovrebbero sicuramente essere i più sicuri.
Notare che diverse shell supportano anche una $'\uXXXX'
notazione per esprimere caratteri basati sul loro punto di codice Unicode. In shell come zsh
e bash
, il carattere viene inserito codificato nel set di caratteri della locale (anche se può causare comportamenti imprevisti se quel set di caratteri non ha quel carattere). Ciò consente di evitare di inserire caratteri non ASCII nel codice della shell.
Quindi sopra:
echo 'voilà' | iconv -f UTF-8 -t //TRANSLIT
echo '詜 reboot'
O:
echo $'voil\u00e0'
echo $'\u8a5c reboot'
(con l'avvertenza che potrebbe rompere la sceneggiatura quando eseguito in locali che non hanno quei caratteri).
O meglio, poiché \
è anche speciale per echo
(o almeno alcune echo
implementazioni, almeno quelle conformi a Unix):
printf '%s\n' 'voilà' | iconv -f UTF-8 -t //TRANSLIT
printf '%s\n' '詜 reboot'
(nota che \
è speciale anche nel primo argomento di printf
, quindi è meglio evitare anche caratteri non ASCII nel caso in cui possano contenere la codifica di \
).
Nota che potresti anche fare:
'echo' 'voilà' | 'iconv' '-f' 'UTF-8' '-t' '//TRANSLIT'
(sarebbe eccessivo ma potrebbe darti un po 'di tranquillità se non sei sicuro di quali personaggi siano nel set portatile)
Assicurati anche di non usare mai l'antica `...`
forma di sostituzione dei comandi (che introduce un altro livello di elaborazione della barra rovesciata), ma usa $(...)
invece.
¹ tecnicamente, echo
viene anche passato come argomento echo
all'utilità (per dirlo come è stato invocato), è il argv[0]
e argc
è 3, anche se nella maggior parte delle shell al giorno d'oggi echo
è incorporato, quindi quello exec()
di un /bin/echo
file con un elenco di 3 argomenti è simulato dal conchiglia. È anche comune considerare l'elenco di argomenti come a partire dal secondo ( argv[1]
a argv[argc - 1]
) in quanto sono quelli sui quali agiscono principalmente i comandi.
² una notevole eccezione a quella che è la ridicola ja_JP.SJIS
localizzazione dei sistemi FreeBSD il cui set di caratteri non ha \
né ~
carattere!
³ nota che mentre molti sistemi (FreeBSD, Solaris, non quelli GNU) considerano U + 00A0 come [[:blank:]]
in locali UTF-8, pochi lo fanno in altri locali come quelli che usano ISO8859-15, forse per evitare questo tipo di problema.