Hva er de praktiske forskjellene mellom Bash og Zsh?

Med nyheten om at Catalina vil være Zsh i stedet for Bash , vil jeg å finne mange resultater som forteller meg om bryteren, og at det kan føre til problemer med skallskript, men jeg er ikke kjent nok med Zsh til å vite hva disse problemene kan være.

Skjellskriptene mine er egentlig ikke så komplisert, men jeg har bare brukt Bash på macOS og Linux – ingen erfaring med Zsh. Kan noen gi en enkel praktisk sammenligning, eller spesifikke snublesteiner jeg trenger å vite, slik at jeg kan begynne å jobbe mot å være klar for nytt skall når Catalina slippes?

Kommentarer

  • All denne hubbubben du har lest er mye å gjøre med ingenting. OS tildeler en » standard » skall når du oppretter nye brukere, ingen grunn til mer. Bash er ikke ‘ t går bort, og du kan bruke det som skallet ditt eller noen av de andre skjellene c tilbudt urrent.
  • Når vi snakket som noen som ‘ brukte begge deler og landet på bash – det eneste som gjorde meg virkelig, dypt misfornøyd med zsh var dens beslutning å bryte POSIX-samsvar når standarden kanoniserer riktignok dårlige designbeslutninger på måter som gjorde det enkelt å bli slurvet om korrekthet når man prøver å skrive manus som trengte å være kompatible med andre, strengt POSIX-superset skall. Dessverre kan den eneste » » være ganske stor. Likevel er ksh93 ikke ‘ t å gå bort, og alle som er seriøse med bash, vil ikke ‘ ikke bruke den eldgamle 3.x-utgivelsen Apple-skip uansett.
  • Som en oppfølging – installerte Catalina i går, byttet til zsh, importerte bash_history og kopierte over noen av mine foretrukne aliaser fra bash_profile, ingenting ser ut til å ha brutt. Setter pris på all informasjonen som er gitt av alle her, og forhåpentligvis hjelper den andre også.
  • @CharlesDuffy: God kommentar. WRT er » seriøs «, og bruker bash version 3.2.57(1): Vet du om Apple bruker bash for noe » viktig » på systemet?

Svar

Først noen viktige ting:

  1. Bash går ikke bort . Hvis du allerede bruker bash, vil ingenting endre seg for deg. Alt som endres er at zsh vil være standard påloggingsskall for nye kontoer, og selv da kan du velge bash i stedet.
  2. Skript påvirkes ikke . Det som endres er skallet for interaktiv bruk, dvs. skallet i terminaler (og også noen få andre ting som bruker påloggingsskallet, for eksempel crontabs). Hvis du har et skript i en fil med kjøringstillatelser, starter du med en shebang-linje , for eksempel #!/bin/bash eller #!/bin/sh eller #!/usr/bin/env bash, det «fortsetter å fungere akkurat som før.
  3. Zsh» s syntaks er ikke helt kompatibel med bash , men det er nært. Mange koder vil fortsette å fungere, for eksempel typiske aliaser og funksjoner. De viktigste forskjellene er i interaktive konfigurasjonsfunksjoner.

Nå, forutsatt at du vurderer å bytte til zsh, som har vært en mulighet i årevis, her er hovedforskjellene du møter. Dette er ikke en uttømmende liste!

Hovedforskjeller for interaktiv bruk

Konfigurasjonsfiler : bash leser (hovedsakelig) .bashrc i interaktive skall som ikke er pålogget (men macOS starter som standard et påloggingsskall i terminaler), .profile eller i påloggingsskjell, og .inputrc. Zsh leser (hovedsakelig) .zshrc (i alle interaktive skall) og .zprofile (i innloggingsskjell). Dette betyr at ingen av bash-tilpasningene dine vil gjelde: du må portere dem. Du kan ikke bare kopiere filene fordi mange ting trenger å finjusteres.

Tastebindinger bruker helt annen syntaks. Bash bruker .inputrc og bind innebygd for å binde nøklene til readline-kommandoer . Zsh bruker bindkey innebygd for å binde nøkler til zle-widgets . De fleste kommandoer med readline har en zsh-ekvivalent, men det er ikke alltid en perfekt ekvivalens.

Når du snakker om tastebindinger, hvis du bruker Vi (m) som redaktør i terminalen, men ikke som kommandolinjemodus i skallet, vil du merke at zsh er standard til redigeringsmodus hvis EDITOR eller VISUAL er satt til vi eller vim . bindkey -e bytter til emacs-modus.

Be : bash setter ledeteksten (hovedsakelig) fra PS1 som inneholder omvendt skråstrek rømmer . Zsh setter ledeteksten hovedsakelig fra PS1 som inneholder prosent rømmer . Funksjonaliteten til bash» s PROMPT_COMMAND er tilgjengelig i zsh via precmd og preexec krokfunksjoner . Zsh har flere bekvemmelighetsmekanismer for å lage fancy instruksjoner, inkludert en rask temamekanisme .

Den grunnleggende kommandolinjelogg mekanismer (navigering med Opp / Ned , søk med Ctrl + R , utvidelse av historikk med !! og venner, siste argument tilbakekalling med Alt + . eller $_) fungerer på samme måte, men det er mange forskjeller i detaljene, for mange til å liste opp her. Du kan kopiere .bash_history til .zsh_history hvis du ikke har endret et skallalternativ som endrer filformatet.

Fullføring : begge skallene er standard til en grunnleggende fullføringsmodus som for det meste fullfører kommando- og filnavn, og bytter til en fancy modus ved inkludert bash_completion på bash eller ved å kjøre compinit i zsh. Du vil finne noen kommandoer som bash håndterer bedre og noen som zsh håndterer bedre. Zsh er vanligvis mer presis, men gir noen ganger opp der bash gjør noe som ikke er riktig, men som er fornuftig. For å spesifisere mulige fullføringer for en kommando, har zsh tre mekanismer:

Mange av bash «s shopt innstillinger har tilsvarende setopt i zsh.

Zsh doe sn «t behandler # som en kommentar start på kommandolinjen som standard, bare i skript (inkludert .zshrc og slikt). For å aktivere interaktive kommentarer, kjør setopt interactive_comments .

Hovedforskjeller for skripting

(og for kraftbrukere på kommandolinjen selvfølgelig)

I bash tar $foo verdien av foo, deler den med mellomromstegn, og for hver del som er separert med mellomrom, hvis den inneholder jokertegn og samsvarer med en eksisterende fil, erstatter mønsteret med listen over treff. For å bare få verdien av foo, trenger du "$foo". Det samme gjelder kommandosubstitusjon $(foo). I zsh er $foo verdien av foo og $(foo) er utdata fra foo minus de endelige nye linjene, med to unntak. Hvis et ord blir tomt på grunn av utvidelse av tomme ikke-siterte variabler, fjernes det (f.eks. a=; b=; printf "%s\n" one "$a$b" three $a$b five skriver ut one, en tom linje, three, five). Resultatet av en ikke-sitert kommandosubstitusjon deles i hvitt mellomrom, men brikkene gjennomgår ikke samsvar med jokertegn.

Bash matriser er indeksert fra 0 til (lengde-1). Zsh-matriser er indeksert fra 1 til lengde. Med a=(one two three), i bash, er ${a[1]} two, men i zsh er det «s one. I bash, hvis du bare refererer til en matrixvariabel uten seler, får du det første elementet, f.eks. $a er one og $a[1] er one[1].I zsh utvides $a til listen over ikke-tomme elementer, og $a[1] utvides til det første elementet. På samme måte er lengden på en matrise i bash ${#a}; dette fungerer også i zsh, men du kan skrive det enklere som $#a. Du kan gjøre 0-indeksering til standard med setopt ksh_arrays ; dette slår også på kravet om å bruke klammeparenteser for å referere til et arrayelement.

Bash har ekstra jokertegnmønstre slik som @(foo|bar) for å matche foo eller bar, som bare er aktivert med shopt -s extglob. I zsh kan du aktivere disse mønstrene med setopt ksh_glob, men det er også en enklere å skrive naturlig syntaks slik som (foo|bar), hvorav noen krever setopt extended_glob (do legg det i .zshrc, og det er som standard i fullføringsfunksjonene). **/ for rekursiv katalogovergang er alltid aktivert i zsh.

I bash, som standard, hvis et jokertegnmønster ikke samsvarer med noen fil, er det igjen uendret. I zsh vil du som standard få en feil, som vanligvis er den sikreste innstillingen. Hvis du vil overføre en jokertegnparameter til en kommando, bruk anførselstegn. Du kan bytte til bash-oppførselen med setopt no_nomatch . Du kan få ikke-samsvarende jokertegnmønstre til å utvides til en tom liste i stedet med setopt null_glob .

I bash går høyre side av en rørledning i en subshell. I zsh kjører den i det overordnede skallet, så du kan skrive ting som somecommand | read output.

Noen fine zsh-funksjoner

Her er noen fine zsh-funksjoner som bash ikke har ( i det minste ikke uten noe alvorlig albuefett). Nok en gang er dette bare et utvalg av de jeg anser som de mest nyttige.

Glob-kvalifiseringskamper tillater samsvarende filer basert på metadata som tidsstempel, størrelse osv. De tillater også tilpasning av utdataene. Syntaksen er ganske kryptisk, men den er ekstremt praktisk. Her er noen eksempler:

  • foo*(.): bare vanlige filer som samsvarer med foo* og symbolske lenker til vanlige filer, ikke kataloger og andre spesielle filer.
  • foo*(*.): bare kjørbare vanlige filer som samsvarer med foo*.
  • foo*(-.): bare vanlige filer som samsvarer med foo*, ikke symbolske lenker og andre spesielle filer.
  • foo*(-@): bare dinglende symbolske lenker som samsvarer med foo*.
  • foo*(om): filene som samsvarer med foo*, sortert etter siste modifikasjonsdato, sist først. Merk at hvis du sender dette til ls, det vil gjøre sin egen sortering. Dette er spesielt nyttig i…
  • foo*(om[1,10]): de 10 siste filene som samsvarer med foo*, de nyeste først.
  • foo*(Lm+1): filer som samsvarer med foo* hvis størrelse er minst 1 MB.
  • foo*(N): samme som foo*, men hvis dette ikke samsvarer med noen fil, kan du lage en tom liste uansett av innstillingen for null_glob -alternativet (se ovenfor).
  • *(D): samsvarer med alle filene inkludert punktfiler ( unntatt . og ..).
  • foo/bar/*(:t) (ved hjelp av en historieendrer ): filene i foo/bar, men med bare grunnnavnet til filen. F.eks. hvis det er en foo/bar/qux.txt, den utvides som qux.txt.
  • foo/bar/*(.:r): ta vanlige filer under foo/bar og fjern utvidelsen. F.eks. foo/bar/qux.txt utvides som foo/bar/qux.
  • foo*.odt(e\""REPLY=$REPLY:r.pdf"\"): ta liste over filer som samsvarer med foo*.odt, og erstatt .odt med .pdf (uansett om PDF filen eksisterer).

Her er noen nyttige zsh-spesifikke jokertegnmønstre .

  • foo*.txt~foobar*: alle .txt filer hvis navn starter med foo men ikke foobar.
  • image<->.jpg(n): alle .jpg filer hvis basenavn er image etterfulgt av et tall, f.eks.image3.jpg og image22.jpg men ikke image-backup.jpg. Glob-kvalifiseringen (n) fører til at filene blir oppført i numerisk rekkefølge, dvs. image9.jpg kommer før image10.jpg (du kan gjøre dette til standard selv uten -n med setopt numeric_glob_sort ).

Til massedøpe filer gir zsh en veldig praktisk verktøy: zmv -funksjonen . Foreslått for .zshrc:

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

Eksempel:

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

Bash har noen få måter å bruke transformasjoner på når verdien av en variabel tas . Zsh har noe av det samme og mange flere .

Zsh har en rekke små praktiske funksjoner for å endre kataloger . Slå på setopt auto_cd for å bytte til en katalog når du skriver inn navnet uten å måtte skrive cd (bash har også dette i dag). Du kan bruke to-argument skjema til cd for å bytte til en katalog med navnet nær den nåværende katalogen . Hvis du for eksempel «er i /some/where/foo-old/deeply/nested/inside og vil gå til /some/where/foo-new/deeply/nested/inside, skriver du bare inn cd old new.

For å tildele en verdi til en variabel, skriver du selvfølgelig VARIABLE=VALUE. For å verdien av en variabel interaktivt, bare kjør vared VARIABLE .

Avsluttende råd

Zsh kommer med et konfigurasjonsgrensesnitt som støtter noen av de vanligste innstillingene, inkludert hermetiserte oppskrifter for ting som store og små bokstaver. (Å) kjøre dette grensesnittet (første linje er ikke nødvendig hvis du bruker en konfigurasjonsfil som er redigert av zsh-newuser-install):

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

Uten boksen, uten konfigurasjonsfil i det hele tatt, er mange av zshs nyttige funksjoner deaktivert for bakoverkompatibilitet med 1990-versjonene. zsh-newuser-install foreslår noen anbefalte funksjoner å slå på.

Det er mange zsh-konfigurasjonsrammer på nettet (mange av dem er på Github ). De kan være en praktisk måte å komme i gang med noen kraftige funksjoner. Baksiden av mynten er at de ofte låser deg i å gjøre ting slik forfatteren gjør, så noen ganger vil de hindre deg i å gjøre ting slik du vil. Bruk dem på egen risiko.

zsh manual har mye informasjon, men den er ofte skrevet på en måte som er kort og vanskelig å følge, og har få eksempler. Ikke nøl med å søke etter forklaringer og eksempler på nettet: hvis du bare bruker delen av zsh som er lett å forstå i håndboken, vil du gå glipp av det. To gode ressurser er adresselisten til zsh-brukere og Unix Stack Exchange . En omfattende samling av artikler om bytte til zsh på mac finner du på scriptingosx.com og er nyttig Ruby-skript for å bringe kommandologgen din med deg , finner du på Github.

Kommentarer

  • Nå lurer jeg ‘ på om den fantastiske ctrl-o fungerer på zsh. Selvfølgelig fungerer det ikke ‘ på Mac OS på bash heller, så det ‘ er egentlig ikke relevant for dette svaret eller nettstedet. Jeg kunne ikke ‘ ikke finne noen informasjon om ctrl-o i zsh i et raskt online søk, men igjen, informasjonen om ctrl-o i bash er også universelt unøyaktig …
  • @Jasper Jeg visste ikke ‘ jeg visste ikke at bash hadde dette. Gjennom beskrivelsen gjør Co det samme i zsh med standard tastebindinger.
  • Jeg var glad for å se at du inkluderte » Noen fine zsh-funksjoner » delen, og les den med engstelse for å prøve å forstå hvorfor Apple kan ha tatt beslutningen om å bytte fra den ekstremt vanlige Bash til den mye mindre populære Zsh. Jeg fant ikke ‘ i det hele tatt, til og med eksternt tvingende der for å rettferdiggjøre bryteren. Det ‘ er åpenbart en ikke-uttømmende liste, men skulle du utelate overskriftene til Zsh fordi de ‘ skulle være åpenbare? Hva mangler jeg her?
  • @CodyGray Jeg vet ikke ‘ og Apple er ikke ‘ t for vane å rettferdiggjøre seg selv. Det kan ha hatt noe å gjøre med at hvis situasjonen hadde blitt omvendt, ville det ikke være ‘ delen «nice bash features».Eller det kan være fordi den siste ikke-GPLv3-basen blir veldig gammel mens zsh har en mer liberal lisens.
  • Min forståelse var at lisensieringen var egentlig den eneste grunnen. Det ‘ er også hvorfor bash på macOS fremdeles er v3. Ordet på gaten er at bash vant ‘ ikke blir oppdatert, og forventningen er at den vil bli fjernet, med mindre sluttbrukeren installerer den via brygge eller etc. Min plan var å bytte til zsh før snarere enn senere for macOS, men holder oss til å bash på Debian for øyeblikket.

Svar

Endre skallet ditt nå og test – du trenger ikke å vente.

chsh -s /bin/zsh 

Jeg vil også anslå at 95% av macOS-brukerne ikke bruker en kommandolinje, og av de som gjør det, trenger 95% ikke å endre noe vesentlig eller alle. (Jeg vil satse på at mer som 10% av de 1% som vet at skjell eksisterer trenger å gjøre noe annet enn å portere et par linjer i .dot-filene sine)

Ledeteksten din endres, og hvis du endret meldingen din på bash, er måten å endre den på zsh ikke vanskeligere og ikke mindre dokumentert enn bash.

De nyere skjellene klarte aldri å komme av bakken hvis de brøt store gjenstander eller forårsaket en smertefull tilpasningsperiode. Hvis du vil ha en mer grunnleggende forandring og virkelig vil ha et skall, må du tenke på og krever trening og intensjon om å adoptere – prøv fisk .

Kommentarer

  • Jeg er i konflikt med fish. Jeg bruker den i to år nå, men inkompatibiliteten til noen kopier / limte enlinjer er slitsom. På den annen side er det et veldig praktisk skall (de automatiske forslagene uten < kbd > Tab < / kbd > er utmerket)
  • Jeg ville elske fisk, jeg vil fortsatt elske fisk, men jeg har for mange skallkonstruksjoner fra et tiår i ksh for å virkelig forlate den folden. Jeg vil gjerne legge bash bak og fullt ut omfavne zsh nå personlig.
  • Jeg er grundig overveldet av fisk. Det er egentlig bare enda et Unix-lignende skall med litt mindre grovhet. (Det står bokstavelig talt » Til slutt, et kommandolinjeskall for 90-tallet » tross alt.) Det eneste nye skallet som Jeg har sett de siste årene som faktisk brakte noe nytt til (mainstream) bordet, var PowerShell, som dessverre var begrenset til Windows altfor lenge, og fortsatt er begrenset til .NET. Det er fremdeles ikke mye nytt i PowerShell som ikke har blitt ‘ t allerede gjort, f.eks. i DCL eller JCL, men det har blitt gjort på en (litt) smakfull måte.
  • @bmike Hvorfor ikke bare bruke ksh, da? Apple sender den nyeste versjonen. Selv poengterte jeg bash for lenge siden og ser ingen grunn til å begynne å bruke zsh nå.
  • Dette svaret beskriver ikke ‘ t forskjellene mellom bash og zsh i det hele tatt skjønt … og jeg ‘ er ikke helt sikker på hvorfor jeg spesifiserer at » 95% av macOS-brukerne ikke ‘ t bruk kommandolinjen » er relevant for et spørsmål om en bruker som åpenbart ikke bruker bash.

Svar

Mine skalleskripter er egentlig ikke så kompliserte

Har shell-skriptene dine shebang-linjer (begynn med #! /bin/bash eller lignende)? Hvis ikke, har du kanskje utilsiktet brukt en bash-funksjon, der den kjører skript uten shebang ved hjelp av bash. Andre skjell, som dash eller zsh, overlater det til operativsystemet, som vanligvis bruker /bin/sh i stedet. /bin/sh på macOS er, og vil sannsynligvis forbli, en kopi av /bin/bash, men utfører bash med navnet sh får den til å ha annen oppførsel. Spesifikasjonene er Bash-manualen, 6.11 Bash POSIX-modus . Noen punkter:

  1. Bash sørger for at POSIXLY_CORRECT -variabelen er satt.

Denne miljøvariabelen kan påvirke oppførselen til en rekke andre verktøy, spesielt hvis du har installert GNU-verktøy.

  1. Erstatning av prosesser er ikke tilgjengelig.

Prosessubstitusjon er <(...) eller >(...) syntaksen.

  1. Innbygningene . og source søker ikke i den nåværende katalogen etter filnavnet argument hvis det ikke blir funnet ved å søke PATH.

Så hvis skriptet ditt gjorde det . foo forventer at den vil hente en fil med navnet foo i den nåværende katalogen, som ikke vil fungere. Du bør gjøre . ./foo i stedet.

Som du kan gjette fra tallene, er det mange mindre forskjeller i oppførselen til bash i POSIX-modus. Bruk best en shebang hvis du mener å bruke bash til skriptene dine.

Kommentarer

  • Når du sjekker ser det ut som det store flertallet av skallskriptene jeg bryter e eller bruk enten eksplisitt state / bin / bash i shebang (veldig få av dem) eller state / bin / sh (nesten alle), slik at i det minste ikke bør være et problem. Takk.
  • Jeg tror prosessutskifting er tilgjengelig nå. Jeg prøvde det også på Catalina. Se: zsh.sourceforge.net/Intro/intro_7.html
  • @Siu vant fremdeles ‘ t hjelpeskripter som bruker /bin/sh eller /bin/bash i shebang. Zsh er bare standard interaktivt skall, det erstattet ikke ‘ bash overalt
  • @muru Ah, jeg forstår. Jeg leste ikke svaret nøye og trodde at forfatteren snakket om prosessubstitusjon er ikke tilgjengelig i zsh 😅

Svar

I ånden av å holde ting enkelt …

Kan noen gi en enkel praktisk sammenligning eller spesifikke snublesteiner jeg trenger å vite, slik at jeg kan begynne å jobbe mot å være klar for det nye skallet når Catalina slippes?

Hvis du tenker å bruke det nye standardskallet, bør du vurdere:

  • Hvis du vil gi Zsh en virvel og føle noen av forskjellene uten å endre skallinnstillingene på maskinen din, kan du prøve Powerline10k i en Docker-beholder og se om det er din kopp te.
  • Hvis du ikke trenger alle klokkene og fløyter og bruk Bash til bare grunnleggende skript, det er ganske enkelt å sette skallet ditt som andre her har forklart. Og hvis du bestemmer deg for ønsker å bruke funksjoner i Bash 5 , det er ganske triviell oppgradering for macOS .
  • Hvis du vil forbedre portabiliteten til skriptene dine, slik at de «er mer sannsynlig å fungere som forventet i begge skallene, teste dem for POSIX-samsvar og fjern eventuelle «bashismer». Jeg har brukt ShellCheck for dette, og det fungerer ganske bra for mindre kompliserte skript.

Selv om ingen bestemt vei er klar disse tre tilnærmingene skal gi deg nok tillit til å ta en informert beslutning uten å overkonstruere problemet eller løsningsområdet.

Legg igjen en kommentar

Din e-postadresse vil ikke bli publisert. Obligatoriske felt er merket med *