Care sunt diferențele practice dintre Bash și Zsh?

Cu știrea că Catalina va fi implicit Zsh în loc de Bash , eu „m găsind o mulțime de rezultate care îmi spun despre comutator și că poate provoca probleme cu scripturile shell, dar nu sunt suficient de familiarizat cu Zsh pentru a ști care ar putea fi aceste probleme.

Scripturile mele shell nu sunt într-adevăr atât de complicat, dar am folosit vreodată Bash pe MacOS și Linux – experiență zero cu Zsh. Poate cineva să ofere o comparație practică simplă sau obstacole specifice pe care trebuie să le știu, astfel încât să pot începe să lucrez pentru a fi pregătit pentru shell nou când Catalina este lansat?

Comentarii

  • Toate aceste discuții pe care le-ați citit sunt mult de făcut în legătură cu nimic. Sistemul de operare atribuie un ” implicit ” shell la crearea de noi utilizatori, fără motiv mai mult. Bash nu merge ‘ departe, și o puteți folosi ca coajă sau ca oricare dintre celelalte cochilii c oferit în prezent.
  • Vorbind ca cineva care ‘ a folosit ambele și a aterizat pe bash – singurul lucru care m-a făcut să fiu foarte profund nemulțumit de zsh a fost decizia sa pentru a sparge conformitatea POSIX atunci când standardul canonizează deciziile de proiectare cu adevărat proaste într-un mod care a făcut mai ușor să devii neglijent în ceea ce privește corectitudinea atunci când încerci să scrii scripturi care trebuiau să fie compatibile cu alte shell-uri superset strict POSIX. Din păcate, acel ” singurul lucru ” poate fi unul destul de mare. Totuși, ksh93 nu ‘ nu va dispărea și oricine ar fi serios în legătură cu bash nu ar folosi ‘ oricum să folosească vechea versiune 3.x lansată de Apple.
  • Ca o continuare – a instalat Catalina ieri, a trecut la zsh, a importat bash_history și a copiat unele dintre pseudonimele mele preferate din bash_profile, nimic nu pare să se fi spart. Apreciați toate informațiile furnizate de toți cei de aici și, sperăm, îi ajută și pe ceilalți.
  • @ CharlesDuffy: Comentariu bun. WRT fiind ” grav ” și utilizând bash version 3.2.57(1): Știți dacă Apple folosește bash pentru orice ” important ” pe sistem?

Răspuns

Mai întâi, câteva lucruri importante:

  1. Bash nu dispare . Dacă folosiți deja bash, nimic nu se va schimba pentru dvs. Tot ce se schimbă este că zsh va fi shell-ul implicit de conectare pentru conturile noi și chiar și atunci puteți selecta bash.
  2. Scripturile nu sunt afectate . Ceea ce se schimbă este shell-ul pentru utilizare interactivă, adică shell-ul din terminale (și, de asemenea, câteva alte lucruri care folosesc shell-ul de conectare, cum ar fi crontabs). Dacă aveți un script într-un fișier cu permisiuni de execuție, începând cu o linie shebang , cum ar fi #!/bin/bash sau #!/bin/sh sau #!/usr/bin/env bash, va continua să funcționeze exact ca înainte.
  3. Sintaxa lui Zsh nu este complet compatibilă cu bash , dar este aproape. O mulțime de cod va continua să funcționeze, de exemplu aliasuri și funcții tipice. Diferențele principale sunt în caracteristicile de configurare interactivă.

Acum, presupunând că vă gândiți să comutați la zsh, care a fost o posibilitate de ani de zile, iată principalele diferențe pe care le veți întâlni. Aceasta nu este o listă exhaustivă!

Principalele diferențe pentru utilizare interactivă

Fișiere de configurare : citește bash (în principal) .bashrc în shell-uri interactive non-login (dar macOS pornește implicit un shell de conectare în terminale), .profile sau în shell-uri de conectare și .inputrc. Zsh citește (în principal) .zshrc (în toate shell-urile interactive) și .zprofile (în shell-uri de conectare). Aceasta înseamnă că nu se va aplica nicio personalizare bash: va trebui să le transferați. Nu puteți copia doar fișierele, deoarece multe lucruri vor trebui modificate.

Legăturile cheie utilizează o sintaxă complet diferită. Bash folosește .inputrc și bind builtin pentru a lega cheile de readline comenzi . Zsh folosește bindkey builtin pentru a lega cheile de widget-uri zle . Majoritatea comenzilor readline au un echivalent zsh, dar nu este întotdeauna o echivalență perfectă.

Apropo de legăturile de taste, dacă utilizați Vi (m) ca editor în terminal, dar nu ca mod de linie de comandă în shell, veți observa implicit zsh la modul de editare vi dacă EDITOR sau VISUAL este setat la vi sau vim . bindkey -e trece la modul emacs.

Prompt : bash setează promptul (în principal) din PS1 care conține backslash scapă . Zsh setează promptul în principal din PS1 care conține procent scapă . Funcționalitatea bash” s PROMPT_COMMAND este disponibilă în zsh prin precmd și preexec funcții de cârlig . Zsh are mai multe mecanisme de comoditate pentru a crea solicitări fanteziste, inclusiv un mecanism tematică prompt .

Elementul de bază istoricul liniei de comandă mecanisme (navigare cu Sus / Jos , căutare cu Ctrl + R , extinderea istoricului cu !! și prieteni, ultimul argument amintit cu Alt + . sau $_) funcționează în același mod, dar există o mulțime de diferențe în detalii, prea multe pentru a fi listate aici. Puteți copia .bash_history în .zsh_history dacă nu ați modificat o opțiune shell care modifică formatul fișierului.

Finalizare : ambele shell-uri implicit la un mod de finalizare de bază care completează în mare parte numele comenzilor și fișierelor și trec la un mod fantezie prin inclusiv bash_completion pe bash sau executând compinit în zsh. Veți găsi câteva comenzi care bash se descurcă mai bine și unele care zsh se descurcă mai bine. Zsh este de obicei mai precis, dar uneori renunță acolo unde bash face ceva care nu este corect, dar este sensibil. Pentru a specifica completările posibile pentru o comandă, zsh are trei mecanisme:

Multe dintre setările bash „s shopt au un corespunzător setopt în zsh.

Zsh doe sn „t trata # ca un comentariu începe în mod implicit pe linia de comandă, numai în scripturi (inclusiv .zshrc și altele). Pentru a activa comentariile interactive, rulați setopt interactive_comments .

Principalele diferențe pentru scripturi

(și, bineînțeles, pentru utilizatorii avansați de pe linia de comandă)

În bash, $foo ia valoarea foo, îl împarte la caractere de spațiu alb și, pentru fiecare parte separată de spațiu, dacă conține caractere wildcard și se potrivește cu un fișier existent, înlocuiește modelul cu lista de potriviri. Pentru a obține doar valoarea foo, aveți nevoie de "$foo". Același lucru este valabil și pentru substituirea comenzilor $(foo). În zsh, $foo este valoarea foo și $(foo) este rezultatul foo minus ultimele linii noi, cu două excepții. Dacă un cuvânt devine gol din cauza extinderii variabilelor necitate necompletate, acesta este eliminat (de ex. a=; b=; printf "%s\n" one "$a$b" three $a$b five imprimă one, o linie goală, three, five). Rezultatul unei înlocuiri de comenzi necotate este împărțit în spațiul alb, dar piesele nu sunt supuse potrivirii cu comodini.

Bash matricile sunt indexate de la 0 la (lungime-1). Tablourile Zsh sunt indexate de la 1 la lungime. Cu a=(one two three), în bash, ${a[1]} este two, dar în zsh, este „s one. În bash, dacă faceți doar referință la o variabilă matrice fără acolade, primiți primul element, de exemplu $a este one și $a[1] este one[1].În zsh, $a se extinde la lista de elemente care nu sunt goale și $a[1] se extinde la primul element. În mod similar, în bash, lungimea unui tablou este ${#a}; acest lucru funcționează și în zsh, dar îl puteți scrie mai simplu ca $#a. Puteți face ca indexarea 0 să fie implicită cu setopt ksh_arrays ; acest lucru activează și cerința de a utiliza paranteze pentru a se referi la un element matrice.

Bash are modele wildcard cum ar fi @(foo|bar) pentru a se potrivi cu foo sau bar, care sunt activate numai cu shopt -s extglob. În zsh, puteți activa aceste modele cu setopt ksh_glob, dar există și un tip mai simplu sintaxă nativă , cum ar fi (foo|bar), dintre care unele necesită setopt extended_glob (faceți puneți-l în .zshrc și este activat în mod implicit în funcțiile de finalizare). **/ pentru traversarea directorului recursiv este întotdeauna activat în zsh.

În bash, în mod implicit, dacă un model wildcard nu se potrivește cu niciun fișier, rămâne neschimbat. În zsh, în mod implicit, veți primi o eroare, care este de obicei cea mai sigură setare. Dacă doriți să transmiteți un parametru wildcard la o comandă, utilizați ghilimele. Puteți comuta la comportamentul bash cu setopt no_nomatch . Puteți face ca tiparele de caractere comodine care nu se potrivesc să se extindă la o listă goală cu setopt null_glob .

În bash, partea dreaptă a unei conducte rulează într-un subshell. În zsh, rulează în shell-ul părinte, deci puteți scrie lucruri precum somecommand | read output.

Câteva caracteristici zsh frumoase

Iată câteva caracteristici zsh frumoase pe care bash nu le are ( cel puțin nu fără o grăsime gravă pentru cot). Încă o dată, aceasta este doar o selecție dintre cele pe care le consider cele mai utile.

Calificatori Glob permite potrivirea fișierelor pe baza metadatelor, cum ar fi ștampila lor, dimensiunea lor, etc. De asemenea, permit modificarea rezultatului. Sintaxa este destul de criptică, dar este extrem de convenabilă. Iată câteva exemple:

  • foo*(.): numai fișierele obișnuite care se potrivesc cu foo* și linkuri simbolice către fișiere obișnuite, nu directoare și alte fișiere speciale.
  • foo*(*.): numai fișiere regulate executabile care se potrivesc cu foo*.
  • foo*(-.): numai fișiere obișnuite care se potrivesc cu foo*, nu linkuri simbolice și alte fișiere speciale.
  • foo*(-@): numai legături simbolice suspendate care se potrivesc cu foo*.
  • foo*(om): fișierele care se potrivesc cu foo*, sortate după data ultimei modificări, cel mai recent mai întâi. Rețineți că, dacă treceți acest lucru către , își va face propria sortare. Acest lucru este util mai ales în …
  • foo*(om[1,10]): cele mai recente 10 fișiere care se potrivesc cu foo*, cel mai recent primul.
  • foo*(Lm+1): fișiere care se potrivesc cu foo* a căror dimensiune este de cel puțin 1 MB.
  • foo*(N): la fel ca foo*, dar dacă acest lucru nu se potrivește cu niciun fișier, produceți o listă goală indiferent setării opțiunii null_glob (vezi mai sus).
  • *(D): potriviți toate fișierele, inclusiv fișierele punct ( cu excepția . și ..).
  • foo/bar/*(:t) (folosind un modificator istoric ): fișierele din foo/bar, dar numai cu numele de bază al fișierului. De exemplu, dacă există a foo/bar/qux.txt, este extins ca qux.txt.
  • foo/bar/*(.:r): luați fișiere obișnuite sub foo/bar și eliminați extensia. De exemplu. foo/bar/qux.txt este extins ca foo/bar/qux.
  • foo*.odt(e\""REPLY=$REPLY:r.pdf"\"): luați lista fișierelor care se potrivesc cu foo*.odt și înlocuiți .odt cu .pdf (indiferent dacă PDF-ul este fișierul există).

Iată câteva utile modele comodine .

  • foo*.txt~foobar*: toate .txt fișiere al căror nume începe cu foo, dar nu foobar.
  • image<->.jpg(n): toate .jpg fișierele al căror nume de bază este image urmat de un număr, de ex.image3.jpg și image22.jpg dar nu image-backup.jpg. Calificatorul glob (n) face ca fișierele să fie listate în ordine numerică, adică image9.jpg apare înainte ca image10.jpg (puteți face acest lucru implicit chiar și fără -n cu setopt numeric_glob_sort ).

Pentru a fișierele de redenumire în masă , zsh oferă o opțiune foarte convenabilă instrument: funcția zmv . Sugerat pentru .zshrc:

autoload zmv alias zcp="zmv -C" zln="zmv -L" 

Exemplu:

zmv "(*).jpeg" "$1.jpg" zmv "(*)-backup.(*)" "backups/$1.$2" 

Bash are câteva moduri de a aplica transformări atunci când se ia valoarea unei variabile . Zsh are unele dintre ele și multe altele .

Zsh are o serie de caracteristici puțin convenabile pentru a schimba directoare . Activați setopt auto_cd pentru a trece la un director când introduceți numele acestuia fără a fi necesar să tastați cd (bash are și asta în zilele noastre). Puteți utiliza formularul cu două argumente în cd pentru a trece la un director al cărui nume este aproape de directorul curent . De exemplu, dacă „intrați în /some/where/foo-old/deeply/nested/inside și doriți să accesați /some/where/foo-new/deeply/nested/inside, tastați doar cd old new.

Pentru a atribui o valoare unei variabile, bineînțeles scrieți VARIABLE=VALUE. Pentru a editați valoarea unei variabile interactiv, trebuie doar să executați vared VARIABLE .

Sfaturi finale

Zsh vine cu o interfață de configurare care acceptă câteva dintre cele mai frecvente setări, inclusiv rețete predefinite pentru lucruri precum completarea fără majuscule între majuscule și minuscule. (prima linie nu este necesară dacă „utilizați un fișier de configurare care a fost editat de zsh-newuser-install):

autoload -U zsh-newuser-install zsh-newuser-install 

În afara cutiei, fără niciun fișier de configurare, multe dintre caracteristicile utile ale zsh sunt dezactivate pentru compatibilitatea cu versiunile din 1990. zsh-newuser-install sugerează câteva caracteristici recomandate pentru a le activa.

Există multe cadre de configurare zsh pe web (multe dintre ele sunt pe Github ). Ele pot fi o modalitate convenabilă de a începe cu câteva caracteristici puternice. Partea inversă a monedei este că te blochează adesea să faci lucrurile așa cum face autorul, așa că uneori te vor împiedica să faci lucrurile așa cum vrei. Folosește-le pe propriul risc.

Manualul zsh conține o mulțime de informații, dar este adesea scris într-un mod care este scurt și greu de urmat și are puține exemple. Nu ezitați să căutați explicații și exemple online: dacă folosiți doar partea de zsh că este ușor de înțeles în manual, veți pierde. Două resurse bune sunt lista de corespondență zsh-users și Unix Stack Exchange . O colecție extinsă de articole despre trecerea la zsh pe Mac poate fi găsită pe scriptingosx.com și un util Scriptul Ruby pentru a vă aduce istoricul comenzilor cu dvs. , poate fi găsit pe Github.

Comentarii

  • Acum ‘ mă întreb dacă uimitorul ctrl-o funcționează pe zsh. Desigur, nici ‘ nu funcționează pe Mac OS pe bash, deci ‘ nu este chiar relevant pentru acest răspuns sau site. Nu am putut ‘ să găsesc informații despre ctrl-o în zsh într-o căutare rapidă online, dar din nou, informațiile despre ctrl-o în bash sunt, de asemenea, universal inexacte …
  • @Jasper Nu știam ‘ nu știam că bash avea acest lucru. Continuând descrierea, Co face același lucru în zsh cu legăturile implicite ale tastelor.
  • M-am bucurat să văd că ați inclus ” Câteva caracteristici frumoase ale zsh secțiunea ” și citiți-o cu nerăbdare pentru a înțelege de ce ar fi putut Apple să ia decizia de a trece de la extrem de obișnuitul Bash la mult mai puțin popularul Zsh. ‘ nu am găsit nimic deloc, chiar de la distanță, care să convingă acolo să justifice comutatorul. Este ‘ în mod evident o listă neexhaustivă, dar omiteați caracteristicile principale ale Zsh deoarece ‘ ar trebui să fie evidente? Ce îmi lipsește aici?
  • @CodyGray Nu știu ‘ și Apple nu are ‘ un obicei de a se justifica. Poate că ar fi avut ceva de-a face cu faptul că, dacă situația ar fi fost inversată, nu ar exista ‘ o secțiune „caracteristici frumoase de bash”.Sau poate fi din cauză că ultimul bash non-GPLv3 devine foarte vechi , în timp ce zsh are o licență mai liberală.
  • Înțelegerea mea a fost că licențierea a fost în esență singurul motiv. De asemenea, este ‘ motivul pentru care bash pe macOS este încă v3. Cuvântul pe stradă este că bash nu va fi actualizat și se așteaptă ca acesta să fie eliminat, cu excepția cazului în care utilizatorul final îl instalează prin brew sau etc. Planul meu era să trec la zsh mai devreme decât mai târziu pentru macOS, dar ținând cont de Debian pentru moment.

Răspuns

Modificare shell-ul dvs. acum și testați – nu este nevoie să așteptați.

chsh -s /bin/zsh 

De asemenea, aș estima că 95% dintre utilizatorii de macOS nu folosesc o linie de comandă, iar dintre cei care o fac, un alt 95% nu va trebui să schimbe nimic semnificativ sau la toate. (Aș paria că este mai mult ca 10% din 1% care știu că există shell-uri trebuie să facă orice altceva decât să porteze câteva linii în fișierele lor .dot)

Solicitarea dvs. se va modifica și dacă ați modificat solicitarea pe bash, modalitatea de a o modifica pe zsh nu este mai dificilă și nu mai puțin documentată decât bash.

Cojile mai noi nu ar reuși să coboare vreodată de la sol dacă ar sparge obiecte majore sau ar provoca o perioadă dureroasă de adaptare. Dacă doriți o schimbare mai fundamentală și doriți cu adevărat o coajă, trebuie să vă gândiți și necesită pregătire și intenție de adoptare – încercați pește .

Comentarii

  • Sunt în conflict cu fish. Îl folosesc de doi ani, dar incompatibilitatea unor rânduri copiate / lipite este obositoare. Pe de altă parte, este un shell foarte la îndemână (sugestiile automate fără < kbd > Tab < / kbd > sunt excelente)
  • Am vrut să iubesc peștele, încă vreau să iubesc peștele, dar am prea multe construcții de coajă dintr-un deceniu în ksh pentru a părăsi cu adevărat acea cutie. Voi lăsa cu bucurie bash-ul în urmă și voi îmbrățișa pe deplin zsh acum, personal.
  • Sunt profund copleșit de pești. Este într-adevăr încă un alt shell asemănător Unix, cu un pic mai puțin cruft. (Se spune literalmente ” În cele din urmă, un shell de linie de comandă pentru anii 90 ” pe pagina de pornire, la urma urmei.) Singurul shell nou care Am văzut în ultimii ani că, de fapt, a adus ceva nou în tabelul (mainstream), a fost PowerShell, care, din păcate, a fost limitat prea mult la Windows și este încă limitat la .NET. Încă nu există atâta noutate în PowerShell care nu a fost deja ‘ făcut deja, de ex. în DCL sau JCL, dar a fost realizat într-un mod (oarecum) bun.
  • @bmike De ce nu folosiți doar ksh, atunci? Apple livrează cea mai recentă versiune. Eu însumi, am dat de bash demult și nu văd niciun motiv să încep să folosesc zsh acum.
  • Acest răspuns nu descrie deloc diferențele dintre bash și zsh deloc. … și ‘ nu știu foarte bine de ce să specific că ” 95% dintre utilizatorii de macOS nu ‘ nu utilizați linia de comandă ” este relevantă pentru o întrebare a unui utilizator care, evident, folosește bash.

Răspuns

Scripturile mele shell nu sunt chiar atât de complicate

Scripturile dvs. shell au linii shebang (începând cu #! /bin/bash sau similar)? Dacă nu, este posibil să fi folosit în mod neintenționat o caracteristică bash, unde rulează scripturi fără un shebang folosind bash. Alte shell-uri, cum ar fi dash sau zsh, îl lasă pe sistemul de operare, care ar folosi de obicei /bin/sh. /bin/sh pe macOS este, și probabil va rămâne, o copie a /bin/bash, dar executând bash cu numele sh face ca acesta să aibă un comportament diferit. Specificațiile sunt manualul Bash, 6.11 Modul POSIX Bash . Unele puncte:

  1. Bash asigură setarea variabilei POSIXLY_CORRECT.

Această variabilă de mediu poate afecta comportamentul mai multor alte instrumente, mai ales dacă aveți instrumente GNU instalate.

  1. Înlocuirea procesului nu este disponibilă.

Înlocuirea procesului este <(...) sau >(...) sintaxă.

  1. Elementele încorporate . și source nu caută în directorul curent numele fișierului argument dacă nu este găsit căutând PATH.

Deci, dacă scriptul dvs. a făcut . foo așteptându-se să obțină un fișier numit foo în directorul curent, care nu a funcționat. În schimb, ar trebui să faci . ./foo.

După cum puteți ghici din cifre, există o mulțime de diferențe minore în comportamentul bash-ului în modul POSIX. Cel mai bine folosiți un shebang dacă doriți să utilizați bash pentru scripturile dvs.

Comentarii

  • La verificare, seamănă cu marea majoritate a script-urilor de shell pe care le erotez e sau folosiți în mod explicit state / bin / bash în shebang (foarte puține dintre ele) sau state / bin / sh (aproape toate), astfel încât cel puțin să nu fie o problemă. Mulțumesc.
  • Cred că înlocuirea procesului este disponibilă acum. Am încercat-o și pe Catalina cu succes. A se vedea: zsh.sourceforge.net/Intro/intro_7.html
  • @Siu a câștigat încă ‘ t ajuta scripturile care folosesc /bin/sh sau /bin/bash în shebang. Zsh este doar shell-ul interactiv implicit, nu ‘ nu a înlocuit bash peste tot
  • @muru Ah, am înțeles. Nu am citit răspunsul cu atenție și am crezut că autorul vorbea despre substituirea procesului nu este disponibil în zsh 😅

Răspuns

În spiritul de a menține lucrurile simple …

Poate cineva să ofere o practică simplă comparație sau obstacole specifice pe care trebuie să le știu, astfel încât să pot începe să lucrez pentru a fi gata pentru noul shell atunci când Catalina este lansată?

Dacă te gândești să folosești noul shell implicit ia în considerare:

  • Dacă vrei să-i faci lui Zsh un vârtej și să simți unele dintre diferențe fără a schimba setările shell-ului pe mașina ta, s-ar putea să încercați Powerline10k într-un container Docker și să vedeți dacă este ceașca dvs. de ceai.
  • Dacă nu aveți nevoie de toate clopotele și fluieră și folosește Bash doar pentru scripturi de bază, este destul de ușor să îți setezi shell-ul, așa cum au explicat alții de aici. Și dacă te hotărăști tu doriți să utilizați funcțiile în Bash 5 este „destul de actualizare trivială pentru macOS .
  • Dacă doriți să îmbunătățiți portabilitatea scripturilor, astfel încât acestea să fie mai susceptibile să funcționeze conform așteptărilor în ambele shell-uri, testați-le pentru conformitatea POSIX și eliminați orice „bashisme”. Am „folosit ShellCheck pentru acest lucru și funcționează destul de bine pentru scripturi mai puțin complicate.

Deși nici o cale anume nu este clară aceste trei abordări ar trebui să vă ofere suficientă încredere pentru a lua o decizie în cunoștință de cauză, fără a înțelege prea mult problema sau spațiul soluției.

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *