Com a notícia de que Catalina usará Zsh em vez de Bash , eu “m encontrando muitos resultados me informando sobre a mudança e que ela pode causar problemas com scripts de shell, mas não estou familiarizado o suficiente com o Zsh para saber quais podem ser esses problemas.
Meus scripts de shell realmente não são é complicado, mas eu só usei o Bash no macOS e no Linux – experiência zero com Zsh. Alguém pode fornecer uma comparação prática simples ou obstáculos específicos que preciso saber, para que possa começar a trabalhar para estar pronto para o novo shell quando Catalina for lançado?
Comentários
Resposta
Primeiro, algumas coisas importantes:
- O Bash não está indo embora . Se você já estiver usando o bash, nada mudará para você. Todas essas mudanças são que zsh será o shell de login padrão para novas contas e, mesmo assim, você pode selecionar bash.
- Os scripts não são afetados . O que muda é o shell para uso interativo, ou seja, o shell nos terminais (e também algumas outras coisas que usam o shell de login, como crontabs). Se você tiver um script em um arquivo com permissões de execução, começando com uma linha shebang , como
#!/bin/bash
ou#!/bin/sh
ou#!/usr/bin/env bash
, ele “continuará funcionando exatamente como antes. - A sintaxe de Zsh” não é totalmente compatível com bash , mas está perto. Muito código continuará funcionando, por exemplo, aliases e funções típicas. As principais diferenças estão nos recursos de configuração interativa.
Agora, supondo que você esteja pensando em trocar para zsh, que tem sido uma possibilidade há anos, aqui estão as principais diferenças que você encontrará. Esta não é uma lista completa!
Principais diferenças para uso interativo
Arquivos de configuração : leituras bash (principalmente) .bashrc
em shells interativos sem login (mas o macOS inicia um shell de login nos terminais por padrão), .profile
ou em shells de login e .inputrc
. Leituras Zsh (principalmente) .zshrc
(em todos os shells interativos) e .zprofile
(em shells de login). Isso significa que nenhuma das personalizações do bash se aplicará: você precisará transferi-los. Você não pode apenas copiar os arquivos porque muitas coisas precisarão de ajustes.
As ligações de teclas usam uma sintaxe completamente diferente. Bash usa .inputrc
e o bind
integrado para vincular chaves a comandos readline . Zsh usa o bindkey
integrado para vincular chaves a widgets zle . A maioria dos comandos readline tem um equivalente zsh, mas nem sempre é uma equivalência perfeita.
Falando em combinações de teclas, se você usar Vi (m) como seu editor no terminal, mas não como seu modo de linha de comando no shell, você notará que o zsh assume o modo de edição vi se EDITOR
ou VISUAL
é definido como vi
ou vim
. bindkey -e
muda para o modo emacs.
Prompt : bash define o prompt (principalmente) de PS1
que contém escapes de barra invertida . Zsh define o prompt principalmente de PS1
que contém escapes de porcentagem . A funcionalidade do bash” s PROMPT_COMMAND
está disponível em zsh por meio de precmd
e preexec
funções de gancho . Zsh tem mecanismos mais convenientes para construir prompts sofisticados, incluindo um mecanismo de tema de prompt .
O histórico da linha de comando mecanismos (navegação com Para cima / Para baixo , pesquise com Ctrl + R , expansão do histórico com !!
e amigos, recuperação do último argumento com Alt + . ou $_
) funcionam da mesma maneira, mas há muitas diferenças nos detalhes, muitos para listar aqui. Você pode copiar seu .bash_history
para .zsh_history
se não tiver alterado uma opção de shell que altera o formato do arquivo.
Conclusão : ambos os shells assumem um modo de preenchimento básico que basicamente completa comandos e nomes de arquivos, e mudam para um modo sofisticado por incluindo bash_completion
no bash ou executando compinit
no zsh. Você encontrará alguns comandos que o bash lida melhor e alguns que o zsh lida melhor. Zsh é geralmente mais preciso, mas às vezes desiste de onde o bash faz algo que não é correto, mas é sensato. Para especificar possíveis completações para um comando, zsh tem três mecanismos:
- O mecanismo de conclusão “antigo” com
compctl
que você pode esquecer. - O “ novo ”mecanismo de conclusão com
compadd
e muitas funções que começam com sublinhado e um poderoso, mas complexo mecanismo de configuração do usuário . - Uma emulação para suporta funções de conclusão do bash que você pode habilitar executando
bashcompinit
. A emulação não é 100% perfeita, mas geralmente funciona.
Muitas das configurações do bash “s shopt
configurações têm uma correspondente setopt
em zsh.
Zsh doe sn “t tratar #
como um comentário inicial na linha de comando por padrão, apenas em scripts (incluindo .zshrc
e outros semelhantes). Para habilitar comentários interativos, execute setopt interactive_comments
.
Principais diferenças para scripts
(e para usuários avançados na linha de comando, é claro)
No bash, $foo
assume o valor de foo
, divide em caracteres de espaço em branco e, para cada parte separada por espaço em branco, se contiver caracteres curinga e corresponder a um arquivo existente, substitui o padrão pela lista de correspondências. Para obter apenas o valor de foo
, você precisa de "$foo"
. O mesmo se aplica à substituição de comando $(foo)
. Em zsh, $foo
é o valor de foo
e $(foo)
é a saída de foo
menos suas novas linhas finais, com duas exceções. Se uma palavra ficar vazia devido à expansão de variáveis vazias não citadas, ela “é removida (por exemplo, a=; b=; printf "%s\n" one "$a$b" three $a$b five
imprime one
, uma linha vazia, three
, five
). O resultado de uma substituição de comando sem aspas é dividido em espaços em branco, mas as partes não passam por correspondência de curinga.
Arrays do Bash são indexados de 0 a (comprimento-1). As matrizes Zsh são indexadas de 1 a comprimento. Com a=(one two three)
, em bash, ${a[1]}
é two
, mas em zsh, é “s one
. No bash, se você apenas referenciar uma variável de matriz sem colchetes, você obtém o primeiro elemento, por exemplo, $a
é one
e $a[1]
é one[1]
.Em zsh, $a
se expande para a lista de elementos não vazios e $a[1]
se expande para o primeiro elemento. Da mesma forma, em bash, o comprimento de uma matriz é ${#a}
; isso também funciona em zsh, mas você pode escrever de forma mais simples como $#a
. Você pode tornar a indexação 0 o padrão com setopt ksh_arrays
; isso também ativa o requisito de usar colchetes para se referir a um elemento de matriz.
O Bash tem extra padrões de caracteres curinga como @(foo|bar)
para corresponder a foo
ou bar
, que só são ativados com shopt -s extglob
. No zsh, você pode ativar esses padrões com setopt ksh_glob
, mas também há um sintaxe nativa tal como (foo|bar)
, algumas das quais requerem setopt extended_glob
(faça coloque-o em seu .zshrc
e ele “está ativado por padrão nas funções de conclusão). **/
para a travessia recursiva do diretório está sempre habilitado no zsh.
No bash, por padrão, se um padrão curinga não corresponder a nenhum arquivo, é o resto inalterado. No zsh, por padrão, você “obterá um erro, que geralmente é a configuração mais segura. Se quiser passar um parâmetro curinga para um comando, use aspas. Você pode mudar para o comportamento do bash com iv id =” 09216eba82 ” setopt null_glob
.
No bash, o lado direito de um pipeline é executado em um subshell. No zsh, ele é executado no shell pai, então você pode escrever coisas como somecommand | read output
.
Alguns recursos zsh interessantes
Aqui estão alguns recursos zsh interessantes que o bash não tem ( pelo menos não sem alguma graxa de cotovelo grave). Mais uma vez, esta é apenas uma seleção das que considero mais úteis.
Qualificadores Glob permite a correspondência de arquivos com base em metadados, como carimbo de data / hora, tamanho, etc. Eles também permitem ajustar a saída. A sintaxe é bastante enigmática, mas é extremamente conveniente. Aqui estão alguns exemplos:
-
foo*(.)
: somente arquivos regulares que correspondem afoo*
e links simbólicos para arquivos regulares, não diretórios e outros arquivos especiais. -
foo*(*.)
: apenas arquivos regulares executáveis correspondentes afoo*
. -
foo*(-.)
: apenas arquivos regulares que correspondem afoo*
, não links simbólicos e outros arquivos especiais. -
foo*(-@)
: apenas links simbólicos pendentes que correspondem afoo*
. -
foo*(om)
: os arquivos correspondentes afoo*
, classificados pela data da última modificação, mais recente primeiro. Observe que se você passar isso parals
, ele fará sua própria classificação. Isso é especialmente útil em… -
foo*(om[1,10])
: os 10 arquivos mais recentes correspondentes afoo*
, os mais recentes primeiro. -
foo*(Lm+1)
: arquivos correspondentes afoo*
cujo tamanho é de pelo menos 1 MB. -
foo*(N)
: o mesmo quefoo*
, mas se isso não corresponder a nenhum arquivo, produz uma lista vazia de qualquer maneira da configuração da opçãonull_glob
(veja acima). -
*(D)
: corresponde a todos os arquivos, incluindo arquivos de ponto ( exceto.
e..
). -
foo/bar/*(:t)
(usando um modificador de histórico ): os arquivos emfoo/bar
, mas apenas com o nome base do arquivo. Por exemplo, se houver afoo/bar/qux.txt
, é expandido comoqux.txt
. -
foo/bar/*(.:r)
: pegue os arquivos normais emfoo/bar
e remova a extensão. Por exemplo.foo/bar/qux.txt
é expandido comofoo/bar/qux
. -
foo*.odt(e\""REPLY=$REPLY:r.pdf"\")
: pegue o lista de arquivos correspondentes afoo*.odt
e substitua.odt
por.pdf
(independentemente de o PDF existe).
Aqui estão alguns padrões úteis de zsh específicos caracteres curinga .
-
foo*.txt~foobar*
: todos.txt
arquivos cujo nome começa comfoo
, mas nãofoobar
. -
image<->.jpg(n)
: todos os.jpg
arquivos cujo nome base éimage
seguido por um número, por exemploimage3.jpg
eimage22.jpg
, mas nãoimage-backup.jpg
. O qualificador glob(n)
faz com que os arquivos sejam listados em ordem numérica, ou seja,image9.jpg
vem antes deimage10.jpg
(você pode torná-lo o padrão mesmo sem-n
comsetopt numeric_glob_sort
).
Para arquivos de renomeação em massa , zsh fornece uma ferramenta muito conveniente ferramenta: a função zmv
. Sugerido para seu .zshrc
:
autoload zmv alias zcp="zmv -C" zln="zmv -L"
Exemplo:
zmv "(*).jpeg" "$1.jpg" zmv "(*)-backup.(*)" "backups/$1.$2"
O Bash tem algumas maneiras de aplicar transformações ao obter o valor de uma variável . Zsh tem algumas das mesmas e muito mais .
Zsh tem uma série de pequenos recursos convenientes para alterar diretórios . Ative setopt auto_cd
para mudar para um diretório quando você digitar seu nome sem ter que digitar cd
(o bash também tem isso hoje em dia). Você pode usar o formulário de dois argumentos para cd
para mudar para um diretório cujo nome está próximo ao diretório atual . Por exemplo, se você “está em /some/where/foo-old/deeply/nested/inside
e deseja ir para /some/where/foo-new/deeply/nested/inside
, basta digitar cd old new
.
Para atribuir um valor a uma variável, você naturalmente escreve VARIABLE=VALUE
. Para editar o valor de uma variável interativamente, basta executar vared VARIABLE
.
Conselho final
Zsh vem com uma interface de configuração que suporta algumas das configurações mais comuns, incluindo receitas enlatadas para coisas como preenchimento sem distinção entre maiúsculas e minúsculas. Para (re) executar esta interface (a primeira linha não é necessária se você estiver usando um arquivo de configuração editado por zsh-newuser-install
):
autoload -U zsh-newuser-install zsh-newuser-install
Fora da caixa, sem nenhum arquivo de configuração, muitos dos recursos úteis do zsh são desabilitados para compatibilidade com versões anteriores de 1990. zsh-newuser-install
sugere alguns recursos recomendados para ativar.
Existem muitos frameworks de configuração zsh na web (muitos deles são no Github ). Eles podem ser uma maneira conveniente de começar a usar alguns recursos poderosos. O outro lado da moeda é que muitas vezes eles o impedem de fazer as coisas da maneira que o autor faz, então às vezes eles o impedem de fazer as coisas da maneira que você deseja. Use-os por sua própria conta e risco.
O O manual zsh contém muitas informações, mas muitas vezes é escrito de uma forma que “é concisa e difícil de seguir e tem poucos exemplos. Não hesite em procurar explicações e exemplos online: se você usar apenas a parte de zsh, isso é fácil de entender no manual, você perderá. Dois bons recursos são a lista de e-mails zsh-users e Unix Stack Exchange . Uma coleção extensa de artigos sobre como mudar para zsh no mac pode ser encontrada em scriptingosx.com e um útil O script Ruby para trazer seu histórico de comandos com você , pode ser encontrado no Github.
Comentários
- Agora eu ‘ estou me perguntando se o incrível ctrl-o funciona no zsh. Claro, ele também não ‘ funciona no Mac OS no bash, então ‘ não é realmente relevante para esta resposta ou site. Não consegui ‘ encontrar qualquer informação sobre ctrl-o no zsh em uma rápida pesquisa online, mas, novamente, as informações sobre ctrl-o no bash também são universalmente imprecisas …
- @Jasper eu não ‘ sabia que o bash tinha isso. Seguindo a descrição, Co faz a mesma coisa em zsh com os atalhos de teclado padrão.
- Fiquei feliz em ver que você incluiu ” Alguns recursos zsh interessantes ” seção e leia-a ansiosamente para tentar entender por que a Apple tomou a decisão de mudar do Bash extremamente comum para o muito menos popular Zsh. Eu não ‘ não encontrei nada nem remotamente convincente para justificar a mudança. É ‘ obviamente uma lista não exaustiva, mas você estava omitindo os recursos de título do Zsh porque ‘ deveriam ser óbvios? O que estou perdendo aqui?
- @CodyGray que eu ‘ não sei e a Apple não ‘ t tem o hábito de se justificar. Pode ter algo a ver com o fato de que, se a situação tivesse sido revertida, não haveria ‘ uma seção de “bons recursos do bash”.Ou pode ser porque o último bash não-GPLv3 está ficando muito velho enquanto o zsh tem uma licença mais liberal.
- Meu entendimento é que o licenciamento era essencialmente a única razão. É ‘ também porque o bash no macOS ainda é v3. O que se diz na rua é que o bash não será ‘ atualizado e a expectativa é de que seja removido, a menos que o usuário final o instale via brew ou etc. Meu plano era mudar para zsh mais cedo ou mais tarde para o macOS, mas mantendo o bash no Debian no momento.
Resposta
Mudança seu shell agora e teste – não há necessidade de esperar.
chsh -s /bin/zsh
- Todos os scripts que dependem de
bash
a sintaxe ainda encontrará e chamará o bash. - o mesmo bash do Mojave está sendo lançado no Catalina e os usuários migrados mantêm seu shell antigo.
- Muitos blogs têm ótimas descrições sobre como mover arquivos de preferência – aqui está um – https://scriptingosx.com/2019/06/moving-to-zsh-part-2-configuration-files/
- Armin transformou sua série de blogs em um livro adequado com cerca de 22 mil palavras.
Além disso, eu estimaria que 95% dos usuários do macOS não usam uma linha de comando e daqueles que usam, outros 95% não terão que mudar nada significativo ou todo. (Eu aposto que é mais como 10% de 1% que sabe que os shells existem precisam fazer qualquer outra coisa além de transportar algumas linhas em seus arquivos .dot)
Seu prompt mudará e se você alterou seu prompt em bash
, a maneira de alterá-lo em zsh
não é mais difícil e nem menos documentado do que bash.
Os projéteis mais novos jamais conseguiriam decolar se quebrassem itens importantes ou causassem um doloroso período de adaptação. Se você deseja uma mudança mais fundamental e realmente deseja uma concha na qual precisa pensar e requer treinamento e intenção de adotar – tente peixe .
Comentários
- Estou em conflito com
fish
. Eu uso há dois anos, mas a incompatibilidade de algumas linhas copiar / colar é cansativa. Por outro lado, é um shell muito útil (as sugestões automáticas sem < kbd > Tab < / kbd > são excelentes) - Eu queria amar peixes, ainda quero amar peixes, mas tenho muitos construtos de conchas de uma década em
ksh
para realmente sair dessa dobra. Ficarei feliz em deixar o bash para trás e abraçar totalmente zsh agora, pessoalmente. - Estou completamente desapontado com peixes. Na verdade, é apenas mais um shell do tipo Unix com um pouco menos de sujeira. (Diz literalmente ” Finalmente, um shell de linha de comando para os anos 90 ” na página inicial, afinal.) O único novo shell que Nos últimos anos, vi que realmente trouxe algo novo para a tabela (principal), foi o PowerShell, que infelizmente ficou confinado ao Windows por muito tempo e ainda está confinado ao .NET. Ainda não há que muito novo no PowerShell que ainda não ‘ tenha sido feito, por exemplo, em DCL ou JCL, mas foi feito de uma forma (um pouco) de bom gosto.
- @bmike Por que não usar apenas ksh, então? A Apple distribui a versão mais atual. Eu mesmo fiz o punhal do bash há muito tempo e não vejo razão para começar a usar zsh agora.
- Esta resposta não ‘ não descreve as diferenças entre bash e zsh de forma alguma … e eu ‘ não tenho certeza por que especificar que ” 95% dos usuários do macOS não ‘ t use a linha de comando ” é relevante para uma pergunta de um usuário que obviamente usa bash.
Resposta
Meus scripts de shell não são realmente tão complicados
Seus scripts de shell têm linhas shebang (começam com #! /bin/bash
ou semelhante)? Caso contrário, você pode ter usado acidentalmente um recurso bash, em que ele executa scripts sem um shebang usando o bash. Outros shells, como dash ou zsh, deixam isso para o sistema operacional, que normalmente usaria /bin/sh
em seu lugar. /bin/sh
no macOS é, e provavelmente continuará sendo, uma cópia de /bin/bash
, mas executando bash com o nome sh
faz com que tenha um comportamento diferente. Os detalhes são o manual do Bash, 6.11 modo Bash POSIX . Alguns pontos:
- O Bash garante que a variável
POSIXLY_CORRECT
seja definida.
Esta variável de ambiente pode afetar o comportamento de várias outras ferramentas, especialmente se você tiver ferramentas GNU instaladas.
- A substituição do processo não está disponível.
A substituição do processo é a sintaxe <(...)
ou >(...)
.
- Os embutidos
.
esource
não procuram o nome do arquivo no diretório atual argumento se não for encontrado pesquisando PATH.
Então, se seu script foi . foo
esperando que ele forneça um arquivo chamado foo
no diretório atual, que não funcionará. Você deve fazer . ./foo
, em vez disso.
Como você pode adivinhar pelos números, existem muitas pequenas diferenças no comportamento do bash no modo POSIX. Melhor usar um shebang se você pretende usar o bash para seus scripts.
Comentários
- Ao verificar, parece que a grande maioria dos scripts de shell que escrevi e ou use explicitamente state / bin / bash no shebang (poucos deles) ou state / bin / sh (quase todos eles), de forma que pelo menos não seja um problema. Obrigado.
- Acho que a substituição de processo já está disponível. Eu também tentei com sucesso em Catalina. Veja: zsh.sourceforge.net/Intro/intro_7.html
- @Siu ainda ganhou ‘ t help scripts que usam
/bin/sh
ou/bin/bash
no shebang. Zsh é apenas o shell interativo padrão, ele não ‘ não substituiu o bash em todos os lugares - @muru Ah, eu entendo. Não li a resposta com atenção e pensei que o autor estava falando sobre a substituição de processo não disponível em
zsh
😅
Resposta
No espírito de manter as coisas simples …
Alguém pode fornecer uma prática simples comparação ou obstáculos específicos que precisarei saber, para poder começar a trabalhar para estar pronto para o novo shell quando Catalina for lançado?
Se você está pensando em usar o novo shell padrão, considere:
- Se você quiser dar uma olhada no Zsh e sentir algumas das diferenças sem alterar as configurações do shell em sua máquina, pode tentar Powerline10k em um contêiner do Docker e ver se é a sua xícara de chá.
- Se você não precisa de todos os sinos e assobia e usa o Bash apenas para scripts básicos, é bastante fácil definir seu shell como outros aqui explicaram. E se você decidir, deseja usar recursos no Bash 5 it “sa bastante atualização trivial para macOS .
- Se você deseja melhorar a portabilidade de seus scripts para que funcionem como esperado em ambos os shells, teste-os para conformidade com POSIX e remova quaisquer “bashismos”. Eu usei o ShellCheck para isso e funciona muito bem para scripts menos complicados.
Embora nenhum caminho específico seja claro essas três abordagens devem dar a você confiança suficiente para tomar uma decisão informada sem sobrecarregar o problema ou espaço de solução.
bash version 3.2.57(1)
: Você sabe se a Apple usabash
para qualquer coisa ” importante ” no sistema?