Con la notizia che Catalina utilizzerà per impostazione predefinita Zsh invece di Bash , io “m trovando molti risultati che mi dicono dello switch e che potrebbe causare problemi con gli script di shell, ma non ho abbastanza familiarità con Zsh per sapere quali potrebbero essere questi problemi.
I miei script di shell in realtà non lo sono è complicato, ma ho sempre usato Bash su macOS e Linux – zero esperienza con Zsh. Qualcuno può fornire un semplice confronto pratico o ostacoli specifici che dovrò conoscere, in modo da poter iniziare a lavorare per essere pronto per il nuova shell quando viene rilasciata Catalina?
Commenti
Risposta
Innanzitutto, alcune cose importanti:
- Bash non andrà via . Se stai già usando bash, non cambierà nulla per te. Tutto ciò che cambia è che zsh sarà la shell di accesso predefinita per i nuovi account, e anche in questo caso, puoi invece selezionare bash.
- Gli script non sono interessati . Ciò che cambia è la shell per luso interattivo, cioè la shell nei terminali (e anche alcune altre cose che usano la shell di login, come i crontabs). Se hai uno script in un file con autorizzazioni di esecuzione, che inizia con una riga shebang come
#!/bin/bash
o#!/bin/sh
o#!/usr/bin/env bash
, continuerà a funzionare esattamente come prima. - La sintassi di Zsh non è completamente compatibile con bash , ma è vicino. Molto codice continuerà a funzionare, ad esempio i tipici alias e funzioni. Le differenze principali sono nelle funzionalità di configurazione interattiva.
Ora, supponendo che tu stia considerando di cambiare a zsh, che è stata una possibilità per anni, ecco le principali differenze che incontrerai. Questo non è un elenco esaustivo!
Principali differenze per luso interattivo
File di configurazione : letture bash (principalmente) .bashrc
nelle shell interattive non di accesso (ma macOS avvia una shell di accesso nei terminali per impostazione predefinita), .profile
o nelle shell di accesso e .inputrc
. Zsh legge (principalmente) .zshrc
(in tutte le shell interattive) e .zprofile
(nelle shell di login). Ciò significa che nessuna delle tue personalizzazioni bash verrà applicata: dovrai trasferirle. Non puoi semplicemente copiare i file perché molte cose avranno bisogno di essere modificate.
Le associazioni di tasti utilizzano una sintassi completamente diversa. Bash utilizza .inputrc
e il bind
integrato per associare le chiavi a comandi readline . Zsh utilizza il bindkey
integrato per associare le chiavi ai widget zle . La maggior parte dei comandi readline ha un equivalente zsh, ma non è sempre unequivalenza perfetta.
Parlando di combinazioni di tasti, se usi Vi (m) come editor nel terminale ma non come modalità della riga di comando nella shell, noterai che zsh è impostato per impostazione predefinita alla modalità di modifica vi se EDITOR
o VISUAL
è impostato su vi
o vim
. bindkey -e
passa alla modalità emacs.
Prompt : bash imposta il prompt (principalmente) da PS1
che contiene escape della barra rovesciata . Zsh imposta il prompt principalmente da PS1
che contiene percentuale di escape . La funzionalità di bash” s PROMPT_COMMAND
è disponibile in zsh tramite precmd
e preexec
funzioni hook . Zsh dispone di meccanismi più pratici per creare prompt fantasiosi, incluso un meccanismo del tema del prompt .
Il cronologia della riga di comando meccanismi (navigazione con Su / Giù , ricerca con Ctrl + R , espansione della cronologia con !!
e amici, richiamo dellultimo argomento con Alt + . o $_
) funzionano allo stesso modo, ma ci sono molte differenze nei dettagli, troppe per essere elencate qui. Puoi copiare il tuo .bash_history
in .zsh_history
se non hai modificato unopzione della shell che cambia il formato del file.
Completamento : entrambe le shell utilizzano per impostazione predefinita una modalità di completamento di base che per lo più completa i nomi di file e comandi e passa a una modalità fantasia tramite incluso bash_completion
su bash o eseguendo compinit
in zsh. Troverai alcuni comandi che bash gestisce meglio e altri che zsh gestisce meglio. Zsh di solito è più preciso, ma a volte rinuncia dove bash fa qualcosa che non è corretto ma è sensato. Per specificare possibili completamenti per un comando, zsh ha tre meccanismi:
- Il “vecchio” meccanismo di completamento con
compctl
che puoi dimenticare. - Il ” nuovo “meccanismo di completamento con
compadd
e molte funzioni che iniziano con il trattino basso e un meccanismo di configurazione utente potente ma complesso . - Unemulazione per supporta le funzioni di completamento bash che puoi abilitare eseguendo
bashcompinit
. Lemulazione non è perfetta al 100% ma di solito funziona.
Molte delle shopt
impostazioni di bash “s setopt
in zsh.
Zsh doe sn “t considera #
come un commento che inizia dalla riga di comando per impostazione predefinita, solo negli script (inclusi .zshrc
e simili). Per abilitare i commenti interattivi, esegui setopt interactive_comments
.
Principali differenze per lo scripting
(e per utenti esperti sulla riga di comando, ovviamente)
In bash, $foo
assume il valore di foo
, lo divide in caratteri di spazio e per ogni parte separata da spazi, se contiene caratteri jolly e corrisponde a un file esistente, sostituisce il modello con lelenco di corrispondenze. Per ottenere solo il valore di foo
, è necessario "$foo"
. Lo stesso vale per la sostituzione dei comandi $(foo)
. In zsh, $foo
è il valore di foo
e $(foo)
è loutput di foo
meno i nuovi caratteri finali, con due eccezioni. Se una parola diventa vuota a causa dellespansione di variabili vuote non quotate, viene rimossa (ad es. a=; b=; printf "%s\n" one "$a$b" three $a$b five
stampa one
, una riga vuota, three
, five
). Il risultato di una sostituzione di comando non quotata viene suddiviso in spazi bianchi, ma le parti non sono soggette a corrispondenza con caratteri jolly.
Gli array Bash sono indicizzati da 0 a (length-1). Gli array Zsh sono indicizzati da 1 alla lunghezza. Con a=(one two three)
, in bash, ${a[1]}
è two
, ma in zsh, “s one
. In bash, se fai riferimento a una variabile di array senza parentesi graffe, ottieni il primo elemento, ad esempio $a
è one
e $a[1]
è one[1]
.In zsh, $a
si espande allelenco di elementi non vuoti e $a[1]
si espande al primo elemento. Allo stesso modo, in bash, la lunghezza di un array è ${#a}
; funziona anche in zsh ma puoi scriverlo più semplicemente come $#a
. Puoi impostare lindicizzazione 0 come predefinita con setopt ksh_arrays
; questo attiva anche la richiesta di utilizzare le parentesi graffe per fare riferimento a un elemento dellarray.
Bash ha modelli di caratteri jolly come @(foo|bar)
per abbinare foo
o bar
, che sono attivati solo con shopt -s extglob
. In zsh, puoi abilitare questi pattern con setopt ksh_glob
, ma esiste anche uno più semplice da digitare sintassi nativa come (foo|bar)
, alcune delle quali richiedono setopt extended_glob
(eseguire mettilo nel tuo .zshrc
, ed è attivo per impostazione predefinita nelle funzioni di completamento). **/
per lattraversamento di directory ricorsivo è sempre abilitato in zsh.
In bash, per impostazione predefinita, se un pattern di caratteri jolly non corrisponde a nessun file, viene lasciato invariato. In zsh, per impostazione predefinita, riceverai un errore, che di solito è limpostazione più sicura. Se desideri passare un parametro jolly a un comando, utilizza le virgolette. Puoi passare al comportamento bash con setopt no_nomatch
. Puoi invece espandere i caratteri jolly non corrispondenti in un elenco vuoto con setopt null_glob
.
In bash, il lato destro di una pipeline viene eseguito in una subshell. In zsh, viene eseguito nella shell padre, quindi puoi scrivere cose come somecommand | read output
.
Alcune belle funzionalità di zsh
Ecco alcune belle funzionalità di zsh che bash non ha ( almeno non senza un po di grasso di gomito serio). Ancora una volta, questa è solo una selezione di quelle che considero più utili.
Qualificatori globali consente la corrispondenza dei file in base a metadati come il loro timestamp, la loro dimensione, ecc. Permettono anche di modificare loutput. La sintassi è piuttosto criptica, ma è estremamente conveniente. Ecco alcuni esempi:
-
foo*(.)
: solo file regolari che corrispondono afoo*
e link simbolici a file normali, non directory e altri file speciali. -
foo*(*.)
: solo file regolari eseguibili corrispondenti afoo*
. -
foo*(-.)
: solo file normali corrispondenti afoo*
, non link simbolici e altri file speciali. -
foo*(-@)
: solo link simbolici pendenti che corrispondono afoo*
. -
foo*(om)
: i file corrispondenti afoo*
, ordinati in base alla data dellultima modifica, a partire dal più recente. Tieni presente che se lo passi als
, eseguirà il proprio ordinamento. Ciò è particolarmente utile in… -
foo*(om[1,10])
: i 10 file più recenti corrispondenti afoo*
, i più recenti per primi. -
foo*(Lm+1)
: file corrispondenti afoo*
la cui dimensione è di almeno 1 MB. -
foo*(N)
: uguale afoo*
, ma se non corrisponde a nessun file, produce un elenco vuoto a prescindere dellimpostazione dellopzionenull_glob
(vedi sopra). -
*(D)
: trova tutti i file inclusi i file punto ( tranne.
e..
). -
foo/bar/*(:t)
(utilizzando un modificatore della cronologia ): i file infoo/bar
, ma con solo il nome di base del file. Ad esempio, se è presente afoo/bar/qux.txt
, è espanso comequx.txt
. -
foo/bar/*(.:r)
: prendi file regolari infoo/bar
e rimuovi lestensione. Per esempio.foo/bar/qux.txt
è espanso comefoo/bar/qux
. -
foo*.odt(e\""REPLY=$REPLY:r.pdf"\")
: prendi il elenco di file corrispondenti afoo*.odt
e sostituire.odt
con.pdf
(indipendentemente dal fatto che il PDF file esistente).
Ecco alcuni utili pattern di caratteri jolly specifici di zsh .
-
foo*.txt~foobar*
: all.txt
file il cui nome inizia confoo
ma nonfoobar
. -
image<->.jpg(n)
: tutti i.jpg
file il cui nome di base èimage
seguito da un numero, ad es.image3.jpg
eimage22.jpg
ma nonimage-backup.jpg
. Il qualificatore glob(n)
fa sì che i file vengano elencati in ordine numerico, ovveroimage9.jpg
precedeimage10.jpg
(puoi impostarlo come predefinito anche senza-n
consetopt numeric_glob_sort
).
Per rinominare in massa i file , zsh fornisce un strumento: la funzione zmv
. Consigliato per il tuo .zshrc
:
autoload zmv alias zcp="zmv -C" zln="zmv -L"
Esempio:
zmv "(*).jpeg" "$1.jpg" zmv "(*)-backup.(*)" "backups/$1.$2"
Bash ha alcuni modi per applicare le trasformazioni quando si prende il valore di una variabile . Zsh ha alcuni degli stessi e molti altri .
Zsh ha una serie di piccole funzioni utili per cambiare directory . Attiva setopt auto_cd
per passare a una directory quando digiti il suo nome senza dover digitare cd
(bash ha anche questo al giorno doggi). Puoi utilizzare il modulo a due argomenti per cd
per passare a una directory il cui nome è vicino alla directory corrente . Ad esempio, se “sei in /some/where/foo-old/deeply/nested/inside
e desideri andare a /some/where/foo-new/deeply/nested/inside
, digita cd old new
.
Per assegnare un valore a una variabile, scrivi ovviamente VARIABLE=VALUE
. Per modifica il valore di una variabile in modo interattivo, basta eseguire vared VARIABLE
.
Consiglio finale
Zsh è dotato di uninterfaccia di configurazione che supporta alcune delle impostazioni più comuni, incluse ricette predefinite per cose come il completamento senza distinzione tra maiuscole e minuscole. Per (ri) eseguire questa interfaccia (la prima riga non è necessaria se stai utilizzando un file di configurazione modificato da zsh-newuser-install
):
autoload -U zsh-newuser-install zsh-newuser-install
Fuori dagli schemi, senza alcun file di configurazione, molte delle utili funzionalità di zsh sono disabilitate per compatibilità con le versioni precedenti degli anni 90. zsh-newuser-install
suggerisce alcune funzionalità consigliate da attivare.
Esistono molti framework di configurazione zsh sul Web (molti di loro sono su Github ). Possono essere un modo conveniente per iniziare con alcune potenti funzionalità. Il rovescio della medaglia è che spesso ti bloccano nel fare le cose come fa lautore, quindi a volte ti impediscono di fare le cose nel modo che desideri. Usali a tuo rischio e pericolo.
Il manuale di zsh contiene molte informazioni, ma spesso è scritto in un modo “conciso e difficile da seguire e contiene pochi esempi. Non esitare a cercare spiegazioni ed esempi online: se usi solo la parte di zsh che è facile da capire nel manuale, ti perderai. Due buone risorse sono la mailing list zsh-users e Unix Stack Exchange . Una vasta raccolta di articoli sul passaggio a zsh su Mac è disponibile su scriptingosx.com e un utile Lo script Ruby per portare con te la cronologia dei comandi , può essere trovato su Github.
Commenti
- Ora ‘ mi chiedo se lincredibile ctrl-o funzioni su zsh. Ovviamente, ‘ non funziona su Mac OS neanche su bash, quindi ‘ non è realmente pertinente per questa risposta o sito. Non sono riuscito ‘ a trovare alcuna informazione su ctrl-o in zsh in una rapida ricerca online, ma anche le informazioni su ctrl-o in bash sono universalmente imprecise …
- @Jasper Non ‘ sapevo che bash avesse questo. Seguendo la descrizione, Co fa la stessa cosa in zsh con le associazioni di tasti predefinite.
- Sono stato contento di vedere che hai incluso ” Alcune belle funzionalità di zsh ” e leggerlo con ansia per cercare di capire perché Apple potrebbe aver deciso di passare dal Bash estremamente comune al meno popolare Zsh. Non ho ‘ trovato nulla, nemmeno lontanamente convincente per giustificare il passaggio. È ‘ ovviamente un elenco non esaustivo, ma stavi omettendo le caratteristiche principali di Zsh perché ‘ dovevano essere ovvie? Cosa mi manca qui?
- @CodyGray Non ‘ so e Apple non è ‘ nellabitudine di giustificarsi. Potrebbe aver avuto qualcosa a che fare con il fatto che se la situazione fosse stata invertita, non ci sarebbe ‘ una sezione “funzioni di bash carine”.Oppure potrebbe essere perché lultima bash non GPLv3 sta diventando molto vecchia mentre zsh ha una licenza più liberale.
- La mia comprensione era che la licenza era essenzialmente lunica ragione. È ‘ anche il motivo per cui bash su macOS è ancora v3. Si dice che bash ‘ non venga aggiornato e si prevede che venga rimosso, a meno che lutente finale non lo installi tramite brew o ecc. Il mio piano era di passare a zsh prima o poi per macOS, ma per il momento attenersi a bash su Debian.
Answer
Cambia la tua shell ora e prova – non cè bisogno di aspettare.
chsh -s /bin/zsh
- Tutti gli script che dipendono da
bash
la sintassi troverà e chiamerà ancora bash. - la stessa bash di Mojave viene spedita su Catalina e gli utenti migrati mantengono la vecchia shell.
- Molti blog hanno ottimi commenti sullo spostamento dei file delle preferenze: eccone uno di questi – https://scriptingosx.com/2019/06/moving-to-zsh-part-2-configuration-files/
- Armin ha trasformato la sua serie di blog in un vero e proprio libro con circa 22.000 parole.
Inoltre, stimerei che il 95% degli utenti di macOS non usa una riga di comando e di quelli che lo fanno, un altro 95% non dovrà cambiare nulla di significativo o tutti. (Scommetto che più del 10% dell1% che sa che esistono shell ha bisogno di fare qualcosa di diverso dal portare un paio di righe nei propri file .dot)
Il tuo prompt cambierà e se hai cambiato il tuo prompt su bash
, il modo per cambiarlo su zsh
non è più difficile e non meno documentato di bash.
I nuovi gusci non riuscirebbero mai a decollare se rompessero oggetti importanti o causassero un doloroso periodo di adattamento. Se vuoi un cambiamento più fondamentale e vuoi davvero una shell a cui devi pensare e che richiede addestramento e intenzione di adottare, prova fish .
Commenti
- Sono in conflitto con
fish
. Lo uso ormai da due anni ma lincompatibilità di alcune righe / incollate è stancante. Daltra parte è una shell molto pratica (i suggerimenti automatici senza < kbd > Tab < / kbd > sono eccellenti) - Volevo amare il pesce, voglio ancora amare il pesce, ma ho troppi costrutti di conchiglie da un decennio in
ksh
per lasciare davvero quella piega. Lascerò volentieri bash alle spalle e abbraccerò completamente zsh ora, personalmente. - Sono completamente deluso dal pesce. In realtà è solo unaltra shell simile a Unix con un po meno cruft. (Dopotutto dice letteralmente ” Infine, una shell a riga di comando per gli anni 90 ” sulla home page, dopotutto.) Lunica nuova shell che Negli ultimi anni ho visto che effettivamente ha portato qualcosa di nuovo alla tabella (mainstream), è stato PowerShell, che sfortunatamente è stato limitato a Windows per troppo tempo ed è ancora limitato a .NET. Non cè ancora quella molto di nuovo in PowerShell che ‘ non sia già stato fatto, ad es. in DCL o JCL, ma è stato fatto in un modo (piuttosto) di buon gusto.
- @bmike Perché non usare semplicemente ksh, allora? Apple fornisce la versione più recente. Io stesso, ho puntato bash molto tempo fa e non vedo alcun motivo per iniziare a usare zsh ora.
- Questa risposta ‘ non descrive affatto le differenze tra bash e zsh … e io ‘ non so perché specificare che ” il 95% degli utenti macOS non ‘ t utilizzare la riga di comando ” è rilevante per una domanda di un utente che ovviamente usa bash.
Risposta
I miei script di shell non sono poi così complicati
I tuoi script di shell hanno righe shebang (iniziano con #! /bin/bash
o simili)? In caso contrario, potresti aver involontariamente utilizzato una funzione bash, in cui esegue script senza uno shebang usando bash. Altre shell, come dash o zsh, lasciano il compito al sistema operativo, che di solito userebbe /bin/sh
. /bin/sh
su macOS è, e probabilmente rimarrà, una copia di /bin/bash
, ma esegue bash con il nome sh
fa sì che abbia un comportamento diverso. Le specifiche sono il manuale di Bash, 6.11 modalità Bash POSIX . Alcuni punti:
- Bash garantisce che la variabile
POSIXLY_CORRECT
sia impostata.
Questa variabile dambiente può influenzare il comportamento di una serie di altri strumenti, specialmente se sono installati strumenti GNU.
- La sostituzione del processo non è disponibile.
La sostituzione del processo è la sintassi <(...)
o >(...)
.
- I comandi incorporati
.
esource
non cercano il nome del file nella directory corrente argomento se non viene trovato cercando PATH.
Quindi, se il tuo script ha . foo
aspettandosi che provenga un file denominato foo
nella directory corrente, che non funzionerà. Dovresti invece eseguire . ./foo
.
Come puoi intuire dai numeri, ci sono molte piccole differenze nel comportamento di bash in modalità POSIX. Meglio usare uno shebang se intendi usare bash per i tuoi script.
Commenti
- Controllando sembra che la stragrande maggioranza degli script di shell che ho scritto e oppure usa esplicitamente state / bin / bash nello shebang (pochissimi) o state / bin / sh (quasi tutti), in modo che almeno non dovrebbe essere un problema. Grazie.
- Penso che la sostituzione del processo sia ora disponibile. Lho provato anche su Catalina con successo. Vedi: zsh.sourceforge.net/Intro/intro_7.html
- @Siu ha ancora vinto ‘ t aiutano gli script che utilizzano
/bin/sh
o/bin/bash
nello shebang. Zsh è solo la shell interattiva predefinita, non ‘ ha sostituito bash ovunque - @muru Ah, ho capito. Non ho letto attentamente la risposta e ho pensato che lautore stesse parlando della sostituzione del processo non è disponibile in
zsh
😅
Risposta
Nello spirito di mantenere le cose semplici …
Qualcuno può fornire un semplice pratico confronto, o blocchi dinciampo specifici che dovrò conoscere, in modo da poter iniziare a lavorare per essere pronto per la nuova shell quando Catalina verrà rilasciato?
Se stai pensando di usare la nuova shell predefinita considera:
- Se vuoi dare a Zsh un vortice e sentire alcune delle differenze senza cambiare le impostazioni della shell sulla tua macchina tu potresti provare Powerline10k in un container Docker e vedere se è la tua tazza di tè.
- Se non hai bisogno di tutti i campanelli e fischietta e usa Bash solo per gli script di base è piuttosto facile impostare la tua shell come altri hanno spiegato. E se decidi tu desidera utilizzare le funzionalità in Bash 5 è “un banale aggiornamento per macOS .
- Se desideri migliorare la portabilità dei tuoi script in modo che “abbiano maggiori probabilità di funzionare come previsto in entrambe le shell, testali per la conformità POSIX e rimuovi qualsiasi “bashismo”. Ho usato ShellCheck per questo e funziona abbastanza bene per script meno complicati.
Anche se nessun percorso particolare è chiaro questi tre approcci dovrebbero darti sufficiente sicurezza per prendere una decisione informata senza progettare eccessivamente il problema o lo spazio della soluzione.
bash version 3.2.57(1)
: Sai se Apple utilizzabash
per qualsiasi cosa ” importante ” nel sistema?