Quais são as diferenças práticas entre Bash e Zsh?

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

  • Todo esse rebuliço que você tem lido tem muito a ver com nada. O sistema operacional atribui um ” shell ” padrão ao criar novos usuários, não há mais motivo. O Bash não ‘ vai fora, e você pode usar isso como sua concha ou qualquer uma das outras conchas c oferecido atualmente.
  • Falando como alguém que ‘ usou os dois e caiu no bash – a única coisa que me deixou realmente, profundamente infeliz com zsh foi sua decisão para quebrar a conformidade POSIX quando o padrão canoniza decisões de design reconhecidamente ruins de maneiras que tornavam fácil ser negligente quanto à correção ao tentar escrever scripts que precisavam ser compatíveis com outros shells superconjunto estritamente POSIX. Infelizmente, essa ” única coisa ” pode ser bem grande. Ainda assim, ksh93 não ‘ vai desaparecer, e qualquer pessoa séria sobre o bash não ‘ usará a versão 3.x antiga que a Apple envia de qualquer maneira.
  • Como acompanhamento – instalei Catalina ontem, mudei para zsh, importei bash_history e copiei alguns dos meus apelidos preferidos de bash_profile, nada parece ter quebrado. Agradeço todas as informações fornecidas por todos aqui e, com sorte, ajudem outras pessoas também.
  • @CharlesDuffy: Bom comentário. WRT sendo ” sério ” e usando bash version 3.2.57(1): Você sabe se a Apple usa bash para qualquer coisa ” importante ” no sistema?

Resposta

Primeiro, algumas coisas importantes:

  1. 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.
  2. 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.
  3. 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:

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 a foo* e links simbólicos para arquivos regulares, não diretórios e outros arquivos especiais.
  • foo*(*.): apenas arquivos regulares executáveis correspondentes a foo*.
  • foo*(-.): apenas arquivos regulares que correspondem a foo*, não links simbólicos e outros arquivos especiais.
  • foo*(-@): apenas links simbólicos pendentes que correspondem a foo*.
  • foo*(om): os arquivos correspondentes a foo*, classificados pela data da última modificação, mais recente primeiro. Observe que se você passar isso para ls, ele fará sua própria classificação. Isso é especialmente útil em…
  • foo*(om[1,10]): os 10 arquivos mais recentes correspondentes a foo*, os mais recentes primeiro.
  • foo*(Lm+1): arquivos correspondentes a foo* cujo tamanho é de pelo menos 1 MB.
  • foo*(N): o mesmo que foo*, mas se isso não corresponder a nenhum arquivo, produz uma lista vazia de qualquer maneira da configuração da opção null_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 em foo/bar, mas apenas com o nome base do arquivo. Por exemplo, se houver a foo/bar/qux.txt, é expandido como qux.txt.
  • foo/bar/*(.:r): pegue os arquivos normais em foo/bar e remova a extensão. Por exemplo. foo/bar/qux.txt é expandido como foo/bar/qux.
  • foo*.odt(e\""REPLY=$REPLY:r.pdf"\"): pegue o lista de arquivos correspondentes a foo*.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 com foo, mas não foobar.
  • image<->.jpg(n): todos os .jpg arquivos cujo nome base é image seguido por um número, por exemploimage3.jpg e image22.jpg, mas não image-backup.jpg. O qualificador glob (n) faz com que os arquivos sejam listados em ordem numérica, ou seja, image9.jpg vem antes de image10.jpg (você pode torná-lo o padrão mesmo sem -n com setopt 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 

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:

  1. 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.

  1. A substituição do processo não está disponível.

A substituição do processo é a sintaxe <(...) ou >(...).

  1. Os embutidos . e source 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.

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *