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
Răspuns
Mai întâi, câteva lucruri importante:
- 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.
- 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. - 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:
- „vechi” mecanism de finalizare cu
compctl
de care puteți uita. - „ nou ”mecanism de completare cu
compadd
și multe funcții care încep cu subliniere și o mecanism puternic, dar complex de configurare a utilizatorului . - O emulare pentru acceptă funcții de finalizare bash pe care le puteți activa rulând
bashcompinit
. Emularea nu este 100% perfectă, dar funcționează de obicei.
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 cufoo*
ș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 cufoo*
. -
foo*(-.)
: numai fișiere obișnuite care se potrivesc cufoo*
, nu linkuri simbolice și alte fișiere speciale. -
foo*(-@)
: numai legături simbolice suspendate care se potrivesc cufoo*
. -
foo*(om)
: fișierele care se potrivesc cufoo*
, 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 cufoo*
, cel mai recent primul. -
foo*(Lm+1)
: fișiere care se potrivesc cufoo*
a căror dimensiune este de cel puțin 1 MB. -
foo*(N)
: la fel cafoo*
, dar dacă acest lucru nu se potrivește cu niciun fișier, produceți o listă goală indiferent setării opțiuniinull_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 dinfoo/bar
, dar numai cu numele de bază al fișierului. De exemplu, dacă există afoo/bar/qux.txt
, este extins caqux.txt
. -
foo/bar/*(.:r)
: luați fișiere obișnuite subfoo/bar
și eliminați extensia. De exemplu.foo/bar/qux.txt
este extins cafoo/bar/qux
. -
foo*.odt(e\""REPLY=$REPLY:r.pdf"\")
: luați lista fișierelor care se potrivesc cufoo*.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 cufoo
, dar nufoobar
. -
image<->.jpg(n)
: toate.jpg
fișierele al căror nume de bază esteimage
urmat de un număr, de ex.image3.jpg
șiimage22.jpg
dar nuimage-backup.jpg
. Calificatorul glob(n)
face ca fișierele să fie listate în ordine numerică, adicăimage9.jpg
apare înainte caimage10.jpg
(puteți face acest lucru implicit chiar și fără-n
cusetopt 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
- Toate scripturile care depind de
bash
sintaxa va găsi și apela în continuare bash. - același bash de la Mojave este livrat pe Catalina, iar utilizatorii migrați își păstrează vechiul shell.
- Multe bloguri au scrieri excelente despre mișcarea fișierelor de preferințe – iată unul dintre acestea – https://scriptingosx.com/2019/06/moving-to-zsh-part-2-configuration-files/
- Armin și-a transformat seria de bloguri într-o carte adecvată cu aproximativ 22.000 de cuvinte.
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:
- 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.
- Înlocuirea procesului nu este disponibilă.
Înlocuirea procesului este <(...)
sau >(...)
sintaxă.
- Elementele încorporate
.
șisource
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.
bash version 3.2.57(1)
: Știți dacă Apple foloseștebash
pentru orice ” important ” pe sistem?