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
Svar
Først nogle vigtige ting:
- 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.
- 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. - 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:
- “gammel” færdiggørelsesmekanisme med
compctl
som du kan glemme alt om. - ” ny “afslutningsmekanisme med
compadd
og mange funktioner, der begynder med understregning og en kraftfuld, men kompleks brugerkonfigurationsmekanisme . - En -emulering til understøtter bash-færdiggørelsesfunktioner , som du kan aktivere ved at køre
bashcompinit
. Emuleringen er ikke 100% perfekt, men den fungerer normalt.
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 matcherfoo*
og symbolske links til almindelige filer, ikke mapper og andre specielle filer. -
foo*(*.)
: kun eksekverbare almindelige filer, der matcherfoo*
. -
foo*(-.)
: kun almindelige filer, der matcherfoo*
, ikke symbolske links og andre specielle filer. -
foo*(-@)
: kun dinglende symbolske links, der matcherfoo*
. -
foo*(om)
: de filer, der matcherfoo*
, sorteret efter sidste ændringsdato, senest først. Bemærk, at hvis du sender dette tills
, det vil foretage sin egen sortering. Dette er især nyttigt i … -
foo*(om[1,10])
: de 10 seneste filer, der matcherfoo*
, de nyeste først. -
foo*(Lm+1)
: filer der matcherfoo*
hvis størrelse er mindst 1 MB. -
foo*(N)
: samme somfoo*
, men hvis dette ikke svarer til nogen fil, skal du oprette en tom liste uanset af indstillingen af indstillingennull_glob
(se ovenfor). -
*(D)
: match alle filer inklusive prikfiler ( undtagen.
og..
). -
foo/bar/*(:t)
(ved hjælp af en historikmodifikator ): filerne ifoo/bar
, men kun med filens basisnavn. F.eks. hvis der er enfoo/bar/qux.txt
, den udvides somqux.txt
. -
foo/bar/*(.:r)
: tag almindelige filer underfoo/bar
og fjern udvidelsen. For eksempel.foo/bar/qux.txt
udvides somfoo/bar/qux
. -
foo*.odt(e\""REPLY=$REPLY:r.pdf"\")
: tag liste over filer, der matcherfoo*.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 medfoo
men ikkefoobar
. -
image<->.jpg(n)
: alle.jpg
filer, hvis basisnavn erimage
efterfulgt af et tal, f.eks.image3.jpg
ogimage22.jpg
men ikkeimage-backup.jpg
. Globkvalifikatoren(n)
får filerne til at blive anført i numerisk rækkefølge, dvs.image9.jpg
kommer førimage10.jpg
(du kan gøre dette til standard selv uden-n
medsetopt 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
- Alle de scripts, der afhænger af
bash
syntaks vil stadig finde og ringe til bash. - den samme bash fra Mojave sendes på Catalina, og migrerede brugere beholder deres gamle skal.
- Mange blogs har store opskrivninger på flytning af præferencefiler – her er en sådan – https://scriptingosx.com/2019/06/moving-to-zsh-part-2-configuration-files/
- Armin forvandlede sin blogserie til en ordentlig bog med omkring 22.000 ord.
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 så 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:
- 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.
- Erstatning af processer er ikke tilgængelig.
Processerstatning er <(...)
eller >(...)
syntaksen.
.
ogsource
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.
bash version 3.2.57(1)
: Ved du, om Apple brugerbash
til noget ” vigtigt ” på systemet?