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
Respuesta
Primero, algunas cosas importantes:
- 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.
- 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. - 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:
- El mecanismo de finalización «antiguo» con
compctl
del que puede olvidarse. - El » nuevo «mecanismo de finalización con
compadd
y muchas funciones que comienzan con guión bajo y un mecanismo de configuración de usuario potente pero complejo . - Una emulación para admite funciones de finalización de bash que puedes habilitar ejecutando
bashcompinit
. La emulación no es 100% perfecta, pero normalmente funciona.
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 confoo*
y enlaces simbólicos a archivos regulares, no directorios y otros archivos especiales. -
foo*(*.)
: solo archivos ejecutables regulares que coincidan confoo*
. -
foo*(-.)
: solo archivos normales que coincidan confoo*
, no enlaces simbólicos y otros archivos especiales. -
foo*(-@)
: solo enlaces simbólicos colgantes que coincidan confoo*
. -
foo*(om)
: los archivos que coinciden confoo*
, ordenados por la fecha de la última modificación, la más reciente primero. Tenga en cuenta que si pasa esto als
, hará su propia clasificación. Esto es especialmente útil en… -
foo*(om[1,10])
: los 10 archivos más recientes que coinciden confoo*
, el más reciente primero. -
foo*(Lm+1)
: archivos que coinciden confoo*
cuyo tamaño sea de al menos 1 MB. -
foo*(N)
: igual quefoo*
, pero si no coincide con ningún archivo, genere una lista vacía independientemente de la configuración de la opciónnull_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 enfoo/bar
, pero solo con el nombre base del archivo. Por ejemplo, si hay afoo/bar/qux.txt
, se expande comoqux.txt
. -
foo/bar/*(.:r)
: tome archivos normales enfoo/bar
y elimine la extensión. P.ej.foo/bar/qux.txt
se expande comofoo/bar/qux
. -
foo*.odt(e\""REPLY=$REPLY:r.pdf"\")
: tome el lista de archivos que coinciden confoo*.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 confoo
pero nofoobar
. -
image<->.jpg(n)
: todos los archivos.jpg
cuyo nombre base esimage
seguido de un número, p. ej.image3.jpg
yimage22.jpg
pero noimage-backup.jpg
. El calificador glob(n)
hace que los archivos se enumeren en orden numérico, es decir,image9.jpg
viene antes deimage10.jpg
(puede hacer que este sea el predeterminado incluso sin-n
consetopt 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
- Todos los scripts que dependen de
bash
la sintaxis seguirá encontrando y llamando a bash. - el mismo bash de Mojave se envía a Catalina y los usuarios migrados mantienen su antiguo shell.
- Muchos blogs tienen excelentes reseñas sobre cómo mover archivos de preferencias; aquí hay uno de ellos: https://scriptingosx.com/2019/06/moving-to-zsh-part-2-configuration-files/
- Armin convirtió su serie de blogs en un libro adecuado con aproximadamente 22k palabras.
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:
- 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.
- La sustitución de procesos no está disponible.
La sustitución del proceso es la sintaxis <(...)
o >(...)
.
- Los elementos internos
.
ysource
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.
bash version 3.2.57(1)
: ¿Sabes si Apple usabash
para cualquier » importante » en el sistema?