¿Cuáles son las diferencias prácticas entre Bash y Zsh?

Con la noticia de que Catalina utilizará de forma predeterminada Zsh en lugar de Bash , «m encontrando muchos resultados que me dicen sobre el cambio, y que puede causar problemas con los scripts de shell, pero no estoy lo suficientemente familiarizado con Zsh para saber cuáles podrían ser esos problemas.

Mis scripts de shell realmente no lo son así de complicado, pero solo he usado Bash en macOS y Linux; sin experiencia con Zsh. ¿Alguien puede proporcionar una comparación práctica simple o los obstáculos específicos que necesitaré saber, para poder comenzar a trabajar para estar listo para el ¿nuevo shell cuando se lance Catalina?

Comentarios

  • Todo este alboroto que has estado leyendo tiene mucho que ver con nada. El SO asigna un » shell » predeterminado al crear nuevos usuarios, no hay razón más. Bash no ‘ de distancia, y puede usar eso como su caparazón o cualquiera de los otros caparazones c ofrecido actualmente.
  • Hablando como alguien que ‘ usó ambos y aterrizó en bash, lo único que me hizo realmente, profundamente infeliz con zsh fue su decisión para romper el cumplimiento de POSIX cuando el estándar canonicaliza las decisiones de diseño admitidamente malas de manera que sea fácil descuidar la corrección al intentar escribir scripts que debían ser compatibles con otros shells de superconjunto estrictamente POSIX. Desafortunadamente, esa » única cosa » puede ser bastante grande. Aún así, ksh93 no ‘ t va a desaparecer, y cualquiera que se tome en serio bash no ‘ usará la versión 3.x antigua de Apple de todos modos.
  • Como seguimiento – instalé Catalina ayer, cambié a zsh, importé bash_history y copié algunos de mis alias preferidos de bash_profile, nada parece haberse roto. Aprecio toda la información proporcionada por todos aquí y espero que también ayude a otros.
  • @CharlesDuffy: Buen comentario. WRT es » serio » y usa bash version 3.2.57(1): ¿Sabes si Apple usa bash para cualquier » importante » en el sistema?

Respuesta

Primero, algunas cosas importantes:

  1. Bash no va a desaparecer . Si ya está usando bash, nada cambiará para usted. Todo lo que cambia es que zsh será el shell de inicio de sesión predeterminado para nuevas cuentas, e incluso entonces, puede seleccionar bash en su lugar.
  2. Los scripts no se ven afectados . Lo que cambia es el shell para uso interactivo, es decir, el shell en terminales (y también algunas otras cosas que usan el shell de inicio de sesión, como crontabs). Si tiene una secuencia de comandos en un archivo con permisos de ejecución, comenzando con una línea shebang como #!/bin/bash o #!/bin/sh o #!/usr/bin/env bash, seguirá funcionando exactamente como antes.
  3. La sintaxis de Zsh no es completamente compatible con bash , pero está cerca. Una gran cantidad de código seguirá funcionando, por ejemplo, alias y funciones típicas. Las principales diferencias están en las características de configuración interactiva.

Ahora, suponiendo que esté considerando cambiar a zsh, que ha sido una posibilidad durante años, aquí están las principales diferencias que encontrará. ¡Esta no es una lista exhaustiva!

Principales diferencias para uso interactivo

Archivos de configuración : lecturas bash (principalmente) .bashrc en shells interactivos sin inicio de sesión (pero macOS inicia un shell de inicio de sesión en terminales de forma predeterminada), .profile o en shells de inicio de sesión y .inputrc. Zsh lee (principalmente) .zshrc (en todos los shells interactivos) y .zprofile (en shells de inicio de sesión). Esto significa que no se aplicará ninguna de sus personalizaciones de bash: tendrá que transferirlas. No puede simplemente copiar los archivos porque habrá que modificar muchas cosas.

Las combinaciones de teclas utilizan una sintaxis completamente diferente. Bash usa .inputrc y el bind incorporado para vincular claves a comandos de readline . Zsh usa el bindkey incorporado para vincular claves a zle widgets . La mayoría de los comandos readline tienen un equivalente zsh, pero no siempre es una equivalencia perfecta.

Hablando de combinaciones de teclas, si usa Vi (m) como su editor en la terminal pero no como su modo de línea de comando en el shell, notará que zsh cambia por defecto al modo de edición vi si EDITOR o VISUAL se establece en vi o vim . bindkey -e cambia al modo emacs.

Prompt : bash establece el indicador (principalmente) de PS1 que contiene la barra invertida se escapa . Zsh establece el mensaje principalmente desde PS1 que contiene porcentaje de escape . La funcionalidad de bash» s PROMPT_COMMAND está disponible en zsh a través de precmd y preexec funciones de gancho . Zsh tiene mecanismos más convenientes para crear mensajes elegantes, incluido un mecanismo de tema de mensajes .

El historial de línea de comando mecanismos (navegación con Arriba / Abajo , busque con Ctrl + R , expansión del historial con !! y amigos, recuperación del último argumento con Alt + . o $_) funcionan de la misma manera, pero hay muchas diferencias en los detalles, demasiadas para enumerarlas aquí. Puede copiar su .bash_history a .zsh_history si no ha cambiado una opción de shell que cambia el formato del archivo.

Finalización : ambos shells están predeterminados en un modo de finalización básico que completa principalmente los nombres de comandos y archivos, y cambian a un modo elegante al incluyendo bash_completion en bash o ejecutando compinit en zsh. Encontrará algunos comandos que bash maneja mejor y otros que zsh maneja mejor. Zsh suele ser más preciso, pero a veces se da por vencido cuando bash hace algo que no es correcto pero es sensato. Para especificar posibles finalizaciones de un comando, zsh tiene tres mecanismos:

Muchas de las shopt configuraciones de bash tienen una correspondiente setopt en zsh.

Zsh doe sn «t tratar # como un comentario que comienza en la línea de comando por defecto, solo en scripts (incluyendo .zshrc y similares). Para habilitar los comentarios interactivos, ejecute setopt interactive_comments .

Principales diferencias para las secuencias de comandos

(y para los usuarios avanzados en la línea de comando, por supuesto)

En bash, $foo toma el valor de foo, lo divide en espacios en blanco, y para cada parte separada por espacios en blanco, si contiene caracteres comodín y coincide con un archivo existente, reemplaza el patrón por la lista de coincidencias. Para obtener el valor de foo, necesita "$foo". Lo mismo se aplica a la sustitución de comandos $(foo). En zsh, $foo es el valor de foo y $(foo) es la salida de foo menos sus últimas líneas nuevas, con dos excepciones. Si una palabra se vuelve vacía debido a la expansión de variables vacías sin comillas, se elimina (p. Ej., a=; b=; printf "%s\n" one "$a$b" three $a$b five imprime one, una línea vacía, three, five). El resultado de una sustitución de comando sin comillas se divide en espacios en blanco, pero las piezas no se combinan con comodines.

Bash matrices se indexan de 0 a (longitud-1). Las matrices Zsh están indexadas de 1 a longitud. Con a=(one two three), en bash, ${a[1]} es two, pero en zsh, es one. En bash, si solo hace referencia a una variable de matriz sin llaves, obtiene el primer elemento, por ejemplo, $a es one y $a[1] es one[1].En zsh, $a se expande a la lista de elementos no vacíos y $a[1] se expande al primer elemento. De manera similar, en bash, la longitud de una matriz es ${#a}; esto también funciona en zsh, pero puede escribirlo de forma más sencilla como $#a. Puede hacer que la indexación 0 sea la predeterminada con setopt ksh_arrays ; esto también activa el requisito de usar llaves para referirse a un elemento de matriz.

Bash tiene extra. patrones de comodines como @(foo|bar) para que coincidan con foo o bar, que solo se habilitan con shopt -s extglob. En zsh, puede habilitar estos patrones con setopt ksh_glob, pero también hay un sintaxis nativa como (foo|bar), algunas de las cuales requieren setopt extended_glob (no póngalo en su .zshrc, y estará activado por defecto en las funciones de finalización). **/ para el recorrido de directorio recursivo siempre está habilitado en zsh.

En bash, de forma predeterminada, si un patrón de comodín no coincide con ningún archivo, se deja sin alterar. En zsh, de forma predeterminada, «obtendrá un error, que suele ser la configuración más segura. Si desea pasar un parámetro comodín a un comando, use comillas. Puede cambiar al comportamiento bash con setopt no_nomatch . Puede hacer que los patrones de comodines que no coincidan se expandan a una lista vacía en su lugar con setopt null_glob .

En bash, el lado derecho de una canalización se ejecuta en una subcapa. En zsh, se ejecuta en la shell principal, por lo que puede escribir cosas como somecommand | read output.

Algunas características agradables de zsh

Aquí hay algunas características agradables de zsh que bash no tiene ( al menos no sin un poco de esfuerzo). Una vez más, esta es solo una selección de las que considero más útiles.

Calificadores Glob permiten archivos coincidentes basados en metadatos como su marca de tiempo, tamaño, etc. También permiten ajustar la salida. La sintaxis es bastante críptica, pero extremadamente conveniente. Aquí hay algunos ejemplos:

  • foo*(.): solo archivos regulares que coinciden con foo* y enlaces simbólicos a archivos regulares, no directorios y otros archivos especiales.
  • foo*(*.): solo archivos ejecutables regulares que coincidan con foo*.
  • foo*(-.): solo archivos normales que coincidan con foo*, no enlaces simbólicos y otros archivos especiales.
  • foo*(-@): solo enlaces simbólicos colgantes que coincidan con foo*.
  • foo*(om): los archivos que coinciden con foo*, ordenados por la fecha de la última modificación, la más reciente primero. Tenga en cuenta que si pasa esto a ls, hará su propia clasificación. Esto es especialmente útil en…
  • foo*(om[1,10]): los 10 archivos más recientes que coinciden con foo*, el más reciente primero.
  • foo*(Lm+1): archivos que coinciden con foo* cuyo tamaño sea de al menos 1 MB.
  • foo*(N): igual que foo*, pero si no coincide con ningún archivo, genere una lista vacía independientemente de la configuración de la opción null_glob (ver arriba).
  • *(D): hacer coincidir todos los archivos, incluidos los archivos dot ( excepto . y ..).
  • foo/bar/*(:t) (usando un modificador de historial ): los archivos en foo/bar, pero solo con el nombre base del archivo. Por ejemplo, si hay a foo/bar/qux.txt, se expande como qux.txt.
  • foo/bar/*(.:r): tome archivos normales en foo/bar y elimine la extensión. P.ej. foo/bar/qux.txt se expande como foo/bar/qux.
  • foo*.odt(e\""REPLY=$REPLY:r.pdf"\"): tome el lista de archivos que coinciden con foo*.odt y reemplace .odt por .pdf (independientemente de si el PDF archivo existe).

Aquí hay algunos patrones de comodines útiles específicos de zsh .

  • foo*.txt~foobar*: todos .txt archivos cuyo nombre comienza con foo pero no foobar.
  • image<->.jpg(n): todos los archivos .jpg cuyo nombre base es image seguido de un número, p. ej.image3.jpg y image22.jpg pero no image-backup.jpg. El calificador glob (n) hace que los archivos se enumeren en orden numérico, es decir, image9.jpg viene antes de image10.jpg (puede hacer que este sea el predeterminado incluso sin -n con setopt numeric_glob_sort ).

Para renombrar archivos en masa , zsh proporciona un método muy conveniente herramienta: la zmv función . Sugerido para su .zshrc:

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

Ejemplo:

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

Bash tiene algunas formas de aplicar transformaciones cuando se toma el valor de una variable . Zsh tiene algunos de los mismos y muchos más .

Zsh tiene una serie de características convenientes para cambiar directorios . Activa setopt auto_cd para cambiar a un directorio cuando escribes su nombre sin tener que escribir cd (bash también tiene esto hoy en día). Puede usar el formulario de dos argumentos para cd para cambiar a un directorio cuyo nombre sea cercano al directorio actual. . Por ejemplo, si «estás en /some/where/foo-old/deeply/nested/inside y quieres ir a /some/where/foo-new/deeply/nested/inside, simplemente escribe cd old new.

Para asignar un valor a una variable, por supuesto, escriba VARIABLE=VALUE. Para editar el valor de una variable de forma interactiva, simplemente ejecute vared VARIABLE .

Consejo final

Zsh viene con una interfaz de configuración que admite algunas de las configuraciones más comunes, incluidas recetas enlatadas para cosas como completar sin distinción entre mayúsculas y minúsculas. Para (re) ejecutar esta interfaz (la primera línea no es necesaria si «estás usando un archivo de configuración que fue editado por zsh-newuser-install):

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

Fuera de la caja, sin ningún archivo de configuración, muchas de las funciones útiles de zsh están deshabilitadas para compatibilidad con versiones anteriores de 1990. zsh-newuser-install sugiere algunas funciones recomendadas para activar.

Hay muchos marcos de configuración de zsh en la web (muchos de ellos son en Github ). Pueden ser una forma conveniente de comenzar con algunas funciones poderosas. La otra cara de la moneda es que a menudo te bloquean para que hagas las cosas de la forma en que lo hace el autor, por lo que a veces te impedirán hacer las cosas como quieres. Úsalos bajo tu propio riesgo.

El manual de zsh tiene mucha información, pero a menudo está escrito de una manera que es concisa y difícil de seguir, y tiene pocos ejemplos. No dude en buscar explicaciones y ejemplos en línea: si solo usa la parte de zsh que es fácil de entender en el manual, te lo perderás. Dos buenos recursos son la lista de correo zsh-users y Unix Stack Exchange . Se puede encontrar una extensa colección de artículos sobre el cambio a zsh en mac en scriptingosx.com y un útil El script Ruby para llevar tu historial de comandos contigo , se puede encontrar en Github.

Comentarios

  • Ahora ‘ me pregunto si el asombroso ctrl-o funciona en zsh. Por supuesto, tampoco ‘ funciona en Mac OS en bash, por lo que ‘ no es realmente relevante para esta respuesta o sitio. No pude ‘ t encontrar información sobre ctrl-o en zsh en una búsqueda rápida en línea, pero, de nuevo, la información sobre ctrl-o en bash también es universalmente inexacta …
  • @Jasper No ‘ no sabía que bash tenía esto. Siguiendo la descripción, Co hace lo mismo en zsh con las combinaciones de teclas predeterminadas.
  • Me alegró ver que incluyó las » Algunas características agradables de zsh «, y léala ansiosamente para tratar de comprender por qué Apple pudo haber tomado la decisión de cambiar del extremadamente común Bash al mucho menos popular Zsh. No ‘ no encontré nada en absoluto ni remotamente convincente allí para justificar el cambio. Es ‘ obviamente una lista no exhaustiva, pero ¿estaba omitiendo las características del título de Zsh porque ‘ se supone que son obvias? ¿Qué me estoy perdiendo aquí?
  • @CodyGray No ‘ no lo sé y Apple no ‘ t habitualmente de justificarse a sí mismos. Puede que haya tenido algo que ver con el hecho de que si la situación se hubiera revertido, no habría ‘ una sección de “buenas características de bash”.O puede ser porque el último bash sin GPLv3 se está volviendo muy antiguo mientras que zsh tiene una licencia más liberal.
  • Mi entendimiento fue que la concesión de licencias era esencialmente la única razón. Es ‘ también la razón por la que bash en macOS sigue siendo v3. Se dice en la calle que bash no ‘ t se actualizará y se espera que se elimine, a menos que el usuario final lo instale a través de brew, etc. Mi plan era cambiar a zsh más temprano que tarde para macOS, pero por el momento se apega a bash en Debian.

Respuesta

Cambiar su shell ahora y pruebe, no es necesario esperar.

chsh -s /bin/zsh 

Además, estimaría que el 95% de los usuarios de macOS no utilizan una línea de comandos y de los que sí lo hacen, otro 95% no tendrá que cambiar nada significativo o al menos todos. (Apuesto a que es más como un 10% del 1% que sabe que existen shells necesita hacer algo más que portar un par de líneas en sus archivos .dot)

Su mensaje cambiará y si cambió su mensaje en bash, la forma de cambiarlo en zsh no es más difícil ni menos documentada que bash.

Los shells más nuevos nunca podrían despegar si rompen elementos importantes o provocan un período de adaptación doloroso. Si desea un cambio más fundamental y realmente desea un caparazón en el que debe pensar y requiere capacitación e intención de adoptarlo, pruebe fish .

Comentarios

  • Estoy en conflicto con fish. Lo uso desde hace dos años, pero la incompatibilidad de algunas líneas uniformes copiadas / pegadas es agotadora. Por otro lado, es un shell muy útil (las sugerencias automáticas sin < kbd > Tab < / kbd > son excelentes)
  • Quería amar el pescado, todavía quiero amar el pescado, pero tengo demasiadas construcciones de concha de una década en ksh para salir de ese pliegue. Con mucho gusto dejaré a bash atrás y aceptaré completamente a zsh ahora, personalmente.
  • Estoy completamente decepcionado con el pescado. En realidad, es solo otro shell similar a Unix con un poco menos de cruft. (Dice literalmente » Finalmente, un shell de línea de comandos para los años 90 » en la página de inicio, después de todo). El único shell nuevo que He visto en los últimos años que realmente trajo algo nuevo a la tabla (convencional), fue PowerShell, que desafortunadamente estuvo confinado a Windows por mucho tiempo, y todavía está confinado a .NET. Todavía no hay eso mucho nuevo en PowerShell que no ‘ t ya se haya hecho, p. Ej. en DCL o JCL, pero se ha hecho de una manera (algo) elegante.
  • @bmike ¿Por qué no usar ksh, entonces? Apple envía la versión más actual. Yo mismo, lancé bash hace mucho tiempo y no veo ninguna razón para empezar a usar zsh ahora.
  • Esta respuesta no ‘ no describe las diferencias entre bash y zsh en absoluto. … y yo ‘ no estoy muy seguro de por qué especificar que » el 95% de los usuarios de macOS no ‘ t use la línea de comando » es relevante para una pregunta de un usuario que obviamente usa bash.

Respuesta

Mis scripts de shell no son realmente tan complicados

¿Sus scripts de shell tienen líneas shebang (comienzan con #! /bin/bash o similar)? De lo contrario, es posible que haya estado usando involuntariamente una función de bash, donde ejecuta scripts sin un shebang usando bash. Otros shells, como dash o zsh, lo dejan en manos del sistema operativo, que normalmente usaría /bin/sh en su lugar. /bin/sh en macOS es, y probablemente seguirá siendo, una copia de /bin/bash, pero ejecutando bash con el nombre sh hace que tenga un comportamiento diferente. Los detalles son el manual Bash, 6.11 modo Bash POSIX . Algunos puntos:

  1. Bash asegura que la variable POSIXLY_CORRECT esté configurada.

Esta variable de entorno puede afectar el comportamiento de varias otras herramientas, especialmente si tiene instaladas herramientas GNU.

  1. La sustitución de procesos no está disponible.

La sustitución del proceso es la sintaxis <(...) o >(...).

  1. Los elementos internos . y source no buscan el nombre de archivo en el directorio actual argumento si no se encuentra buscando PATH.

Entonces, si su secuencia de comandos lo hizo . foo esperando que obtenga un archivo llamado foo en el directorio actual, que no funcionará. Debería hacer . ./foo en su lugar.

Como puede adivinar por los números, hay muchas diferencias menores en el comportamiento de bash en el modo POSIX. Es mejor usar un shebang si quiere usar bash para sus scripts.

Comentarios

  • Al verificar, parece que la gran mayoría de los scripts de shell escribí eo use explícitamente state / bin / bash en el shebang (muy pocos de ellos) o state / bin / sh (casi todos), por lo que al menos no debería ser un problema. Gracias.
  • Creo que la sustitución de procesos ya está disponible. También lo probé en Catalina con éxito. Ver: zsh.sourceforge.net/Intro/intro_7.html
  • @Siu ganó ‘ t ayuda a los scripts que usan /bin/sh o /bin/bash en el shebang. Zsh es solo el shell interactivo predeterminado, no ‘ reemplazó a bash en todas partes
  • @muru Ah, lo entiendo. No leí la respuesta con atención y pensé que el autor estaba hablando de que la sustitución de procesos no está disponible en zsh 😅

Respuesta

Con el espíritu de mantener las cosas simples …

¿Alguien puede proporcionar una simple práctica comparación, o obstáculos específicos que necesitaré saber, de modo que pueda comenzar a trabajar para estar listo para el nuevo shell cuando se lance Catalina?

Si estás pensando en usar el nuevo shell predeterminado, considera:

  • Si quieres darle un giro a Zsh y sentir algunas de las diferencias sin cambiar la configuración del shell en tu máquina, podría probar Powerline10k en un contenedor Docker y ver si es su taza de té.
  • Si no necesita todas las campanas y silbidos y usar Bash solo para scripts básicos, es bastante fácil configurar su shell como lo han explicado otros aquí. Y si decide que desea usar funciones en Bash 5 , es una actualización bastante trivial para macOS .
  • Si desea mejorar la portabilidad de sus scripts para que sea más probable que funcionen como se espera en ambos shells, pruébelos para que cumplan con POSIX y elimine los «bashismos». «He usado ShellCheck para esto y funciona bastante bien para scripts menos complicados.

Aunque no hay una ruta en particular clara estos tres enfoques deberían darle suficiente confianza para tomar una decisión informada sin sobrepasar el espacio del problema o la solución.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *