Quali sono le differenze pratiche tra Bash e Zsh?

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

  • Tutto questo frastuono che hai letto è molto da fare per nulla. Il sistema operativo assegna un ” default ” shell durante la creazione di nuovi utenti, nessun motivo di più. Bash non è ‘ di distanza, e puoi usarlo come shell o come qualsiasi altra shell c attualmente offerto.
  • Parlando come qualcuno che ‘ ha usato entrambi ed è atterrato su bash – lunica cosa che mi ha reso veramente, profondamente insoddisfatto di zsh è stata la sua decisione infrangere la conformità POSIX quando lo standard canonizza decisioni di progettazione decisamente sbagliate in modi che rendevano facile essere sciatti sulla correttezza quando si cerca di scrivere script che dovevano essere compatibili con altre shell con superset rigorosamente POSIX. Sfortunatamente, quella ” unica cosa ” può essere piuttosto grande. Tuttavia, ksh93 ‘ non andrà via, e chiunque sia serio riguardo a bash non ‘ utilizzerà comunque lantica versione 3.x fornita da Apple.
  • Come seguito: ho installato Catalina ieri, passato a zsh, importato bash_history e copiato alcuni dei miei alias preferiti da bash_profile, niente sembra essersi rotto. Apprezzo tutte le informazioni fornite da tutti qui e si spera che aiutino anche gli altri.
  • @CharlesDuffy: buon commento. WRT è ” serio ” e utilizza bash version 3.2.57(1): Sai se Apple utilizza bash per qualsiasi cosa ” importante ” nel sistema?

Risposta

Innanzitutto, alcune cose importanti:

  1. 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.
  2. 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.
  3. 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:

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 a foo* e link simbolici a file normali, non directory e altri file speciali.
  • foo*(*.): solo file regolari eseguibili corrispondenti a foo*.
  • foo*(-.): solo file normali corrispondenti a foo*, non link simbolici e altri file speciali.
  • foo*(-@): solo link simbolici pendenti che corrispondono a foo*.
  • foo*(om): i file corrispondenti a foo*, ordinati in base alla data dellultima modifica, a partire dal più recente. Tieni presente che se lo passi a ls, eseguirà il proprio ordinamento. Ciò è particolarmente utile in…
  • foo*(om[1,10]): i 10 file più recenti corrispondenti a foo*, i più recenti per primi.
  • foo*(Lm+1): file corrispondenti a foo* la cui dimensione è di almeno 1 MB.
  • foo*(N): uguale a foo*, ma se non corrisponde a nessun file, produce un elenco vuoto a prescindere dellimpostazione dellopzione null_glob (vedi sopra).
  • *(D): trova tutti i file inclusi i file punto ( tranne . e ..).
  • foo/bar/*(:t) (utilizzando un modificatore della cronologia ): i file in foo/bar, ma con solo il nome di base del file. Ad esempio, se è presente a foo/bar/qux.txt, è espanso come qux.txt.
  • foo/bar/*(.:r): prendi file regolari in foo/bar e rimuovi lestensione. Per esempio. foo/bar/qux.txt è espanso come foo/bar/qux.
  • foo*.odt(e\""REPLY=$REPLY:r.pdf"\"): prendi il elenco di file corrispondenti a foo*.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 con foo ma non foobar.
  • image<->.jpg(n): tutti i .jpg file il cui nome di base è image seguito da un numero, ad es.image3.jpg e image22.jpg ma non image-backup.jpg. Il qualificatore glob (n) fa sì che i file vengano elencati in ordine numerico, ovvero image9.jpg precede image10.jpg (puoi impostarlo come predefinito anche senza -n con setopt 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 

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:

  1. 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.

  1. La sostituzione del processo non è disponibile.

La sostituzione del processo è la sintassi <(...) o >(...).

  1. I comandi incorporati . e source 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.

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *