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/basho#!/bin/sho#!/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 
compctldel que puede olvidarse. -  El » nuevo «mecanismo de finalización con 
compaddy 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/bary elimine la extensión. P.ej.foo/bar/qux.txtse expande comofoo/bar/qux. -  
foo*.odt(e\""REPLY=$REPLY:r.pdf"\"): tome el lista de archivos que coinciden confoo*.odty reemplace.odtpor.pdf(independientemente de si el PDF archivo existe). 
Aquí hay algunos patrones de comodines útiles específicos de zsh .
-  
foo*.txt~foobar*: todos.txtarchivos cuyo nombre comienza confoopero nofoobar. -  
image<->.jpg(n): todos los archivos.jpgcuyo nombre base esimageseguido de un número, p. ej.image3.jpgyimage22.jpgpero noimage-backup.jpg. El calificador glob(n)hace que los archivos se enumeren en orden numérico, es decir,image9.jpgviene antes deimage10.jpg(puede hacer que este sea el predeterminado incluso sin-nconsetopt 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 
bashla 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 
kshpara 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_CORRECTesté 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
 .ysourceno 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/sho/bin/bashen 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 usabashpara cualquier » importante » en el sistema?