¿Qué hacen realmente `\ time`,` t \ ime` y `\ cd`? (Diversión con barras invertidas en conchas)

9

Mientras discutía sobre las diferencias entre /usr/bin/timey el shell (bash y zsh) incorporado time, alguien mencionó que se puede usar \timecomo una abreviatura para obtener /usr/bin/time.

Primero parecía un buen atajo inocente, pero luego surgieron algunas preguntas:

  • ¿Por qué t\imefunciona también?
  • ¿Por qué \cdcambia el directorio, aunque /usr/bin/cd¹ no?

Entonces, obviamente, \foono es equivalente a $(which foo). La pregunta ahora es:

¿El comportamiento observado \footanto en bash como en zsh está cubierto de alguna manera por la definición POSIX de un shell, y si es así, por qué se comporta como lo hace?


Nota 1: /usr/bin/cdes, en mi sistema,

#!/bin/sh
builtin cd "$@"
Jonas Schäfer
fuente
También vea unix.stackexchange.com/questions/12762/… Tenga en cuenta que \ command está específicamente documentado en la funcionalidad tcsh que dice ignorar los alias para el comando.
simpleuser

Respuestas:

14

t\imeo \cd(o "tim"eo 'cd'o ${-##*}timeo ${-+time}y cualquier otra combinación de citas y expansiones en las que pueda pensar que eventualmente se resolvería timeo cd), es eso: otra forma de escribir cdy time.

Sin embargo, que con el tiempo a resolver cdo timeen un momento posterior del analizador sintáctico de la cáscara y la interpretación. En particular, eso sucede mucho después de que se produce el reconocimiento de palabras clave de shell y la sustitución de alias .

Entonces, en el momento en que el shell busca palabras clave en su idioma, no lo reconoce ti\mecomo la timepalabra clave del shell. Entonces a:

ti\me echo test

sería reconocido por el shell como un comando simple en lugar de la timepalabra clave seguida de un comando simple.

Luego ti\me, se procesaría la cita (aquí la barra invertida está citando el mcarácter que no necesita cita de todos modos, el carácter de cita se elimina, se obtiene time) y se buscaría un time comando como cualquier otro comando (en la lista de incorporados , funciones y archivos ejecutables $PATH. Lo más probable es que esté /bin/timeaquí)

Para cd, no hay cdpalabra clave en el lenguaje de shell, solo un cdcomando incorporado (que tiene prioridad sobre su /usr/bin/cd). Sin embargo, si define un alias para cd(like alias cd=pushd), lo mismo de nuevo. Como la sustitución de alias se realiza muy temprano, antes de eliminar las comillas, si tiene un alias para cdy no uno para \cd(tenga en cuenta que no muchos shells permiten alias con barras invertidas en ellos), luego escribiendo:

\cd dir

te estás asegurando de que tu cdalias no esté sustituido.

En resumen, citando un nombre de comando o cualquier parte de ella le impide ser visto como una palabra clave de shell (palabras clave ser cosas como while, for, if, {... timees una palabra clave en algunos sólo conchas), y no pasa por un alias que pueda tener para él .

Sin embargo, no obliga a ese comando a resolverse en un archivo ejecutable $PATH, el comando todavía se busca primero entre las funciones (que puede solucionar haciendo command time cmd...) y las incorporadas (que puede solucionar haciendo env time cmd..., aunque no sé de un shell que tiene un timecomando incorporado ).

Tenga en cuenta que las citas también pueden influir en el comportamiento de los componentes especiales de la familia typeset/ declare/ export/ local... en algunos depósitos. Consulte ¿Se necesitan cotizaciones para la asignación de variables locales? para detalles.

Stéphane Chazelas
fuente
Entonces, la diferencia entre timey lo cdque conduce a la diferencia en el comportamiento observado es que timees una palabra clave y cdes un comando incorporado .
Jonas Schäfer
1
@JonasWielicki, es que timees una palabra clave y cdno lo es. (y si tuviera un alias para cdo time, eso sería otro asunto). Eso cdestá incorporado o no tiene incidencia en este punto (en lo que respecta a la influencia de las citas). Sin embargo, algunos shells tienen algunas incorporaciones que están a medio camino entre las palabras clave y las incorporadas, ya que su análisis se realiza de manera diferente a otras incorporaciones. Ese es el caso de export/ typeset/ declare. Probablemente debería agregar alguna nota al respecto en esta respuesta.
Stéphane Chazelas