Hvad er de praktiske forskelle mellem Bash og Zsh?

Med nyheden om, at Catalina vil som standard være Zsh i stedet for Bash , jeg “m at finde mange resultater, der fortæller mig om kontakten, og at det kan forårsage problemer med shell-scripts, men jeg er ikke fortrolig med Zsh til at vide, hvad disse problemer kan være.

Mine shell-scripts er virkelig ikke så kompliceret, men jeg har kun nogensinde brugt Bash på macOS og Linux – ingen erfaring med Zsh. Kan nogen give en simpel praktisk sammenligning eller specifikke snublesten, jeg bliver nødt til at kende, så jeg kan begynde at arbejde hen imod at være klar til ny skal, når Catalina frigives?

Kommentarer

  • Al denne hubbub, som du har læst, er meget at gøre ved ingenting. OS tildeler en ” standard ” shell, når du opretter nye brugere, ingen grund mere. Bash er ikke ‘ t går væk, og du kan bruge det som din skal eller en hvilken som helst af de andre skaller c tilbydes urent.
  • Når vi taler som en person, der ‘ brugte begge og landede på bash – det eneste, der gjorde mig virkelig, dybt utilfreds med zsh var dens beslutning at bryde POSIX-overholdelse, når standarden kanoniserer ganske vist dårlige designbeslutninger på måder, der gjorde det let at blive sjusket om korrekthed, når man prøver at skrive scripts, der skulle være kompatible med andre strengt POSIX-superset-skaller. Desværre kan den ” eneste ting ” være ret stor. Stadig ksh93 er ikke ‘ t går væk, og enhver, der er seriøs omkring bash, ville ikke ‘ ikke bruge den gamle 3.x-frigivelse af Apple-skibe under alle omstændigheder.
  • Som opfølgning – installerede Catalina i går, skiftede til zsh, importerede bash_history og kopierede over nogle af mine foretrukne aliaser fra bash_profile, intet ser ud til at være brudt. Værdsat alle de oplysninger, der er leveret af alle her, og forhåbentlig hjælper det også andre.
  • @CharlesDuffy: God kommentar. WRT er ” seriøs ” og bruger bash version 3.2.57(1): Ved du, om Apple bruger bash til noget ” vigtigt ” på systemet?

Svar

Først nogle vigtige ting:

  1. Bash forsvinder ikke . Hvis du allerede bruger bash, vil der ikke ændre sig noget for dig. Alt, hvad der ændrer sig, er, at zsh vil være standard login-shell til nye konti, og selv da kan du vælge bash i stedet.
  2. Scripts påvirkes ikke . Hvad der ændrer sig er shell til interaktiv brug, dvs. shell i terminaler (og også et par andre ting, der bruger login shell, såsom crontabs). Hvis du har et script i en fil med eksekveringstilladelser, startende med en shebang-linje såsom #!/bin/bash eller #!/bin/sh eller #!/usr/bin/env bash, det “fortsætter med at arbejde nøjagtigt som før.
  3. Zsh” s syntaks er ikke helt kompatibel med bash , men det er tæt. En masse kode vil fortsætte med at fungere, for eksempel typiske aliasser og funktioner. De vigtigste forskelle er i interaktive konfigurationsfunktioner.

Nu forudsat at du overvejer at skifte til zsh, som har været en mulighed i årevis, her er de vigtigste forskelle, du vil støde på. Dette er ikke en udtømmende liste!

Hovedforskelle til interaktiv brug

Konfigurationsfiler : bash læser (hovedsageligt) .bashrc i ikke-login interaktive skaller (men macOS starter som standard en login-shell i terminaler), .profile eller i login-skaller og .inputrc. Zsh læser (hovedsageligt) .zshrc (i alle interaktive skaller) og .zprofile (i login-skaller). Dette betyder, at ingen af dine bash-tilpasninger finder anvendelse: du skal portere dem. Du kan ikke bare kopiere filerne, fordi mange ting skal justeres.

Tastebindinger bruger en helt anden syntaks. Bash bruger .inputrc og bind indbygget til at binde nøgler til readline-kommandoer . Zsh bruger bindkey builtin til at binde nøgler til zle-widgets . De fleste kommandoer med readline har en zsh-ækvivalent, men det er ikke altid en perfekt ækvivalens.

Når vi taler om tastebindinger, hvis du bruger Vi (m) som din in-terminal editor, men ikke som din kommandolinjemodus i shell, vil du bemærke, at zsh er standard til vi redigeringstilstand, hvis EDITOR eller VISUAL er indstillet til vi eller vim . bindkey -e skifter til emacs-tilstand.

Spørg : bash indstiller prompten (hovedsageligt) fra PS1 , som indeholder backslash undslipper . Zsh indstiller prompten hovedsageligt fra PS1 som indeholder procent undgår . Funktionen af bash” s PROMPT_COMMAND er tilgængelig i zsh via precmd og preexec krogfunktioner . Zsh har flere bekvemmelighedsmekanismer til at oprette smarte meddelelser, herunder en hurtig temamekanisme .

Den grundlæggende kommandolinjeshistorie mekanismer (navigation med op / ned , søg med Ctrl + R , historieudvidelse med !! og venner, sidste argument tilbagekaldes med Alt + . eller $_) fungerer på samme måde, men der er mange forskelle i detaljerne, for mange til at nævne her. Du kan kopiere din .bash_history til .zsh_history hvis du ikke har ændret en shell-indstilling, der ændrer filformatet.

Afslutning : begge skaller er standard til en grundlæggende færdiggørelsestilstand, der for det meste udfylder kommando- og filnavne, og skifter til en fancy tilstand ved inklusive bash_completion på bash eller ved at køre compinit i zsh. Du vil finde nogle kommandoer, der bash håndterer bedre, og nogle, som zsh håndterer bedre. Zsh er normalt mere præcis, men giver undertiden op, hvor bash gør noget, der ikke er korrekt, men som er fornuftigt. For at specificere mulige udfyldelser for en kommando har zsh tre mekanismer:

Mange af bash “s shopt indstillinger har en tilsvarende setopt i zsh.

Zsh doe sn “t behandler # som en kommentar start som standard på kommandolinjen, kun i scripts (inklusive .zshrc og sådan). For at aktivere interaktive kommentarer skal du køre setopt interactive_comments .

Hovedforskelle ved scripting

(og selvfølgelig for strømbrugere på kommandolinjen)

I bash tager $foo værdien af foo, deler det med tegn i mellemrum, og for hver del der er adskilt mellemrum, hvis det indeholder jokertegn og matcher en eksisterende fil, erstatter mønsteret med listen over matches. For bare at få værdien af foo skal du have "$foo". Det samme gælder kommandoerstatning $(foo). I zsh er $foo værdien af foo og $(foo) er output fra foo minus de endelige nye linjer med to undtagelser. Hvis et ord bliver tomt på grund af ekspanderende tomme ikke-citerede variabler, fjernes det (f.eks. a=; b=; printf "%s\n" one "$a$b" three $a$b five udskriver one, en tom linje, three, five). Resultatet af en ikke-citeret kommandosubstitution er opdelt i det hvide rum, men brikkerne gennemgår ikke jokertegn.

Bash arrays indekseres fra 0 til (længde-1). Zsh-arrays indekseres fra 1 til længde. Med a=(one two three) i bash er ${a[1]} two, men i zsh er det “s one. I bash, hvis du bare henviser til en arrayvariabel uden seler, får du det første element, f.eks. $a er one og $a[1] er one[1].I zsh udvides $a til listen over ikke-tomme elementer, og $a[1] udvides til det første element. På samme måde er længden af en matrix i bash ${#a}; dette fungerer også i zsh, men du kan skrive det mere simpelt som $#a. Du kan gøre 0-indeksering til standard med setopt ksh_arrays ; dette tænder også kravet om at bruge seler til at henvise til et arrayelement.

Bash har ekstra jokertegnemønstre såsom @(foo|bar) for at matche foo eller bar, som kun er aktiveret med shopt -s extglob. I zsh kan du aktivere disse mønstre med setopt ksh_glob, men der er også en enklere at skrive native syntaks såsom (foo|bar), hvoraf nogle kræver setopt extended_glob (do sæt det i din .zshrc, og det er som standard aktiveret i afslutningsfunktioner). **/ til rekursiv bibliotekstrafik er altid aktiveret i zsh.

I bash, hvis et jokertegnmønster ikke matcher nogen fil, er det som standard tilbage uændret. I zsh får du som standard en fejl, som normalt er den sikreste indstilling. Hvis du vil overføre en wildcard-parameter til en kommando, skal du bruge anførselstegn. Du kan skifte til bash-opførsel med setopt no_nomatch . Du kan få ikke-matchende jokertegnemønstre til at udvides til en tom liste i stedet med setopt null_glob .

I bash kører den højre side af en pipeline i en subshell. I zsh kører den i den overordnede shell, så du kan skrive ting som somecommand | read output.

Nogle gode zsh-funktioner

Her er et par gode zsh-funktioner, som bash ikke har ( i det mindste ikke uden noget alvorligt albuefedt). Endnu en gang er dette bare et udvalg af dem, som jeg anser for mest nyttige.

Glob-kvalifikationer tillader matchende filer baseret på metadata som f.eks. deres tidsstempel, deres størrelse osv. De tillader også tilpasning af output. Syntaksen er temmelig kryptisk, men den er yderst praktisk. Her er et par eksempler:

  • foo*(.): kun almindelige filer, der matcher foo* og symbolske links til almindelige filer, ikke mapper og andre specielle filer.
  • foo*(*.): kun eksekverbare almindelige filer, der matcher foo*.
  • foo*(-.): kun almindelige filer, der matcher foo*, ikke symbolske links og andre specielle filer.
  • foo*(-@): kun dinglende symbolske links, der matcher foo*.
  • foo*(om): de filer, der matcher foo*, sorteret efter sidste ændringsdato, senest først. Bemærk, at hvis du sender dette til ls, det vil foretage sin egen sortering. Dette er især nyttigt i …
  • foo*(om[1,10]): de 10 seneste filer, der matcher foo*, de nyeste først.
  • foo*(Lm+1): filer der matcher foo* hvis størrelse er mindst 1 MB.
  • foo*(N): samme som foo*, men hvis dette ikke svarer til nogen fil, skal du oprette en tom liste uanset af indstillingen af indstillingen null_glob (se ovenfor).
  • *(D): match alle filer inklusive prikfiler ( undtagen . og ..).
  • foo/bar/*(:t) (ved hjælp af en historikmodifikator ): filerne i foo/bar, men kun med filens basisnavn. F.eks. hvis der er en foo/bar/qux.txt, den udvides som qux.txt.
  • foo/bar/*(.:r): tag almindelige filer under foo/bar og fjern udvidelsen. For eksempel. foo/bar/qux.txt udvides som foo/bar/qux.
  • foo*.odt(e\""REPLY=$REPLY:r.pdf"\"): tag liste over filer, der matcher foo*.odt, og erstat .odt med .pdf (uanset om PDF filen findes).

Her er et par nyttige zsh-specifikke wildcard mønstre .

  • foo*.txt~foobar*: alle .txt filer hvis navn starter med foo men ikke foobar.
  • image<->.jpg(n): alle .jpg filer, hvis basisnavn er image efterfulgt af et tal, f.eks.image3.jpg og image22.jpg men ikke image-backup.jpg. Globkvalifikatoren (n) får filerne til at blive anført i numerisk rækkefølge, dvs. image9.jpg kommer før image10.jpg (du kan gøre dette til standard selv uden -n med setopt numeric_glob_sort ).

Til masseomdøb filer giver zsh en meget praktisk værktøj: funktionen zmv . Foreslået til din .zshrc:

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

Eksempel:

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

Bash har et par måder at anvende transformationer på, når man tager værdien af en variabel . Zsh har noget af det samme og mange flere .

Zsh har et antal små praktiske funktioner til at ændre mapper . Tænd setopt auto_cd for at skifte til en mappe, når du skriver navnet uden at skulle skrive cd (bash har også dette i dag). Du kan bruge form med to argumenter til cd for at skifte til en mappe, hvis navn er tæt på den aktuelle mappe . Hvis du f.eks. “Er i /some/where/foo-old/deeply/nested/inside og vil gå til /some/where/foo-new/deeply/nested/inside, skal du bare skrive cd old new.

For at tildele en værdi til en variabel, skal du selvfølgelig skrive VARIABLE=VALUE. Til rediger værdien af en variabel interaktivt, kør bare vared VARIABLE .

Endelig rådgivning

Zsh leveres med en konfigurationsgrænseflade, der understøtter et par af de mest almindelige indstillinger, herunder dåse opskrifter til ting som store og små bogstaver. For at (gen) køre denne grænseflade (den første linje er ikke nødvendig, hvis du bruger en konfigurationsfil, der er redigeret af zsh-newuser-install):

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

Uden for boksen uden nogen konfigurationsfil overhovedet, er mange af zshs nyttige funktioner deaktiveret for bagudkompatibilitet med 1990-versionerne. zsh-newuser-install foreslår nogle anbefalede funktioner, der skal aktiveres.

Der er mange zsh-konfigurationsrammer på nettet (mange af dem er på Github ). De kan være en bekvem måde at komme i gang med nogle kraftige funktioner. Bagsiden af mønten er, at de ofte låser dig i at gøre tingene som forfatteren gør, så nogle gange forhindrer de dig i at gøre tingene som du vil. Brug dem på egen risiko.

zsh manual har en masse information, men den er ofte skrevet på en måde, der er kort og vanskelig at følge og har få eksempler. Tøv ikke med at søge efter forklaringer og eksempler online: hvis du kun bruger den del af zsh der er let at forstå i manualen, vil du gå glip af. To gode ressourcer er zsh-brugeres mailingliste og Unix Stack Exchange . En omfattende samling af artikler om skift til zsh på mac kan findes på scriptingosx.com og et nyttigt Ruby-script til at bringe din kommandohistorik med dig findes på Github.

Kommentarer

  • Nu ‘ spekulerer på, om den fantastiske ctrl-o fungerer på zsh. Det fungerer selvfølgelig ikke ‘ på Mac OS på bash, så det ‘ er ikke rigtig relevant for dette svar eller dette sted. Jeg kunne ikke ‘ ikke finde nogen oplysninger om ctrl-o i zsh i en hurtig online-søgning, men så igen, oplysningerne om ctrl-o i bash er også universelt unøjagtige …
  • @Jasper Jeg vidste ikke ‘ jeg vidste ikke, at bash havde dette. Går efter beskrivelsen gør Co det samme i zsh med standardnøglebindingerne.
  • Jeg var glad for at se, at du inkluderede ” Nogle gode zsh-funktioner ” sektionen, og læs det med ængstelse for at prøve at forstå, hvorfor Apple muligvis har taget beslutningen om at skifte væk fra den ekstremt almindelige Bash til den meget mindre populære Zsh. Jeg fandt ‘ slet ikke noget, endda fjernt overbevisende der for at retfærdiggøre skiftet. Det ‘ er tydeligvis en ikke-udtømmende liste, men skulle du udelade overskriftsfunktionerne i Zsh, fordi de ‘ skulle være åbenlyse? Hvad mangler jeg her?
  • @CodyGray Jeg ved ikke ‘ og Apple er ikke ‘ t for vane at retfærdiggøre sig selv. Det kan have haft noget at gøre med det faktum, at hvis situationen var vendt, ville der ikke være ‘ et “nice bash features” afsnit.Eller det kan være fordi den sidste ikke-GPLv3-bash bliver rigtig gammel , mens zsh har en mere liberal licens.
  • Min forståelse var, at licensen var stort set den eneste grund. Det ‘ er også grunden til, at bash på macOS stadig er v3. Ord på gaden er, at bash vandt ‘ t opdateres, og forventningen er, at den vil blive fjernet, medmindre slutbrugeren installerer det via brygge osv. Min plan var at skifte til zsh før snarere end senere til macOS, men holder sig til bash på Debian for øjeblikket.

Svar

Skift din shell nu og test – ingen grund til at vente.

chsh -s /bin/zsh 

Jeg vil også anslå, at 95% af macOS-brugerne ikke bruger en kommandolinje, og af dem der gør det, behøver en anden 95% ikke at ændre noget væsentligt eller ved alle. (Jeg vil sige det mere som 10% af de 1%, der ved, at der findes skaller, skal gøre andet end at portere et par linjer i deres .dot-filer)

Din prompt bliver ændret, og hvis du ændrede din prompt på bash, er måden at ændre den på zsh ikke sværere og ikke mindre dokumenteret end bash.

De nyere skaller ville aldrig komme af jorden, hvis de brød store ting eller forårsagede en smertefuld tilpasningsperiode. Hvis du vil have en mere grundlæggende ændring og virkelig vil have en skal, skal du tænke over og kræver træning og intention om at vedtage – prøv fisk .

Kommentarer

  • Jeg er i konflikt med fish. Jeg bruger det i to år nu, men inkompatibiliteten mellem nogle kopier / indsatte enlinjer er trættende. På den anden side er det en meget praktisk skal (de automatiske forslag uden < kbd > Tab < / kbd > er fremragende)
  • Jeg ville elske fisk, jeg vil stadig elske fisk, men jeg har for mange skalkonstruktioner fra et årti i ksh for nogensinde at forlade den fold. Jeg vil gerne efterlade bash og omfavne zsh nu personligt.
  • Jeg er grundigt overvældet af fisk. Det er egentlig bare endnu en Unix-lignende skal med lidt mindre groft. (Der står bogstaveligt talt ” Endelig en kommandolinjeskal til 90erne ” trods alt.) Den eneste nye skal, der Jeg har set i de seneste år, der faktisk bragte noget nyt til (mainstream) -tabellen, var PowerShell, som desværre var begrænset til Windows alt for længe og stadig er begrænset til .NET. Der er stadig ikke meget nyt i PowerShell, der ikke allerede er gjort ‘ f.eks. i DCL eller JCL, men det er gjort på en (noget) smagfuld måde.
  • @bmike Hvorfor ikke bare bruge ksh, da? Apple sender den nyeste version. Selv pointerede jeg bash for længe siden og ser ingen grund til at begynde at bruge zsh nu.
  • Dette svar beskriver ‘ t overhovedet ikke forskellene mellem bash og zsh … og jeg ‘ er ikke helt sikker på, hvorfor jeg angiver, at ” 95% af macOS-brugerne ikke ‘ Brug kommandolinjen ” er relevant for et spørgsmål om en bruger, der naturligvis bruger bash.

Svar

Mine shell-scripts er virkelig ikke så komplicerede

Har dine shell-scripts shebang-linjer (begynder med #! /bin/bash eller lignende)? Hvis ikke, har du muligvis utilsigtet brugt en bash-funktion, hvor den kører scripts uden en shebang ved hjælp af bash. Andre skaller, som bindestreg eller zsh, overlader det til operativsystemet, som normalt bruger /bin/sh i stedet. /bin/sh på macOS er og forbliver sandsynligvis en kopi af /bin/bash, men udfører bash med navnet sh får det til at have en anden adfærd. Specifikationerne er Bash-manualen, 6.11 Bash POSIX-tilstand . Nogle punkter:

  1. Bash sikrer, at variablen POSIXLY_CORRECT er indstillet.

Denne miljøvariabel kan påvirke adfærden for en række andre værktøjer, især hvis du har installeret GNU-værktøjer.

  1. Erstatning af processer er ikke tilgængelig.

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

  1. . og source indbyggede søger ikke i det aktuelle bibliotek efter filnavnet argument, hvis det ikke findes ved at søge PATH.

Så hvis dit script gjorde . foo forventer, at den kilder en fil med navnet foo i den aktuelle mappe, der ikke fungerer. Du skal . ./foo i stedet.

Som du kan gætte ud fra tallene, er der mange mindre forskelle i opførsel af bash i POSIX-tilstand. Brug bedst en shebang, hvis du mener at bruge bash til dine scripts.

Kommentarer

  • Når det kontrolleres, ser det ud til, at langt størstedelen af de shell-scripts, jeg knuste e eller brug enten eksplicit state / bin / bash i shebang (meget få af dem) eller state / bin / sh (næsten alle), så det i det mindste ikke burde være et problem. Tak.
  • Jeg tror, procesudskiftning er tilgængelig nu. Jeg prøvede det også med succes på Catalina. Se: zsh.sourceforge.net/Intro/intro_7.html
  • @Siu vandt stadig ‘ t hjælp scripts, der bruger /bin/sh eller /bin/bash i shebang. Zsh er kun den interaktive standardskal, den erstattede ikke ‘ t bash overalt
  • @muru Ah, jeg forstår. Jeg læste ikke omhyggeligt svaret og troede, at forfatteren talte om proceserstatning er ikke tilgængelig i zsh 😅

Svar

I ånden med at holde tingene enkle …

Kan nogen give en simpel praktisk sammenligning eller specifikke snublesten, jeg bliver nødt til at vide, så jeg kan begynde at arbejde på at være klar til den nye skal, når Catalina frigives?

Hvis du tænker ved hjælp af den nye standardskal, overvej:

  • Hvis du vil give Zsh en hvirvel og føle nogle af forskellene uden at ændre skalindstillingerne på din maskine, prøv muligvis Powerline10k i en Docker-container og se om det er din kop te.
  • Hvis du ikke har brug for alle klokkerne og fløjter og brug Bash til bare grundlæggende scripts, er det ret nemt at indstille din skal, som andre her har forklaret. Og hvis du beslutter dig for vil bruge -funktioner i Bash 5 , det er en triviel opgradering til macOS .
  • Hvis du vil forbedre bærbarheden af dine scripts, så de “er mere tilbøjelige til at fungere som forventet i begge skaller, test dem for POSIX-overholdelse og fjern eventuelle “bashismer”. Jeg har brugt ShellCheck til dette, og det fungerer ret godt for mindre komplicerede scripts.

Selvom ingen bestemt sti er klar disse tre tilgange skal give dig tilstrækkelig tillid til at træffe en informeret beslutning uden at overkonstruere problemet eller løsningsområdet.

Skriv et svar

Din e-mailadresse vil ikke blive publiceret. Krævede felter er markeret med *