¿Por qué importa la secuencia en la ejecución de estos comandos bash?

10

Parece que hay alguna inconsistencia que no puedo entender con respecto al bash shell.

Si ejecuto:

ls;date;time

Los resultados de las tres consultas se muestran en secuencia.

Sin embargo, al intercambiar la fecha y la hora, aparece un mensaje de error.

Entonces si ejecuto:

ls;time;date

el mensaje de error dice: bash: syntax error near unexpected token 'date'.

¿Alguien puede explicar esto?

rohitvijaysharma
fuente
Su problema radica en time;datecontra date;time. Esto parece ser un problema con la canalización bashy el último carácter generado con la timesalida. Los resultados probados en diferentes emuladores de terminal son: - [Bash] $ date; time # [OK] $ time; date # [ NotOK ] bash: error de sintaxis cerca del token inesperado `date '$ time # solo el error no parece ser el resultado de cualquier fecha. - [Csh] $ date; time # [OK] $ time; date # [OK] - [Tcsh] $ date; time # [OK] $ time; date # [OK] - [Ksh] $ date; time # [ OK] $ time; fecha # [OK]
Mostafa Shahverdy
He actualizado mi respuesta con una explicación para el mensaje de error. Por favor, compruebe que esta es la respuesta que estaba buscando.
zwets

Respuestas:

10

El timecomando en su canalización no es el /usr/bin/timebinario, sino el bash timeincorporado. Comparar man timecon help time. El error que ve es que bash no puede analizar timeel argumento. Esto debe estar presente o ser una nueva línea. Es una nueva línea en su primer ejemplo pero ausente en el segundo.

Por otro lado, si tuvieras que correr

ls;date;'time'

o

ls;'time';date

donde las comillas 'time'revocan su estado como una palabra reservada, entonces bash no tiene problemas al analizar la línea. Ahora analiza tres comandos en una lista, que ejecutará en secuencia, e /usr/bin/timeinformará un error de uso en cualquier caso.

Apéndice

Se observó que aunque time ; dateproduce un error, time ; ; dateno lo hace. La explicación probable es que time ;bash interpreta que es equivalente a time <newline>. La expresión time ; ; datese analiza luego como la lista de time ;y date.

Esto es coherente con la observación de que time ;y también time ; ;son legales, el segundo se analiza como la lista de singleton que contiene time ;seguido del punto y coma opcional permitido después de las listas.

Entonces, otra forma de explicar por qué time ; dateproduce el error bash: syntax error near unexpected token 'date'es que timeconsume el punto y coma que lo separa date. Solo puede hacer eso porque timees una palabra reservada bash.

zwets
fuente
Gracias por una buena explicación! Pero, de nuevo, este comportamiento me parece un error: timese supone que permite un comando NULL, y se supone que el punto y coma delimita las listas, por lo que el timecomando IMO no debe "consumir" el punto y coma después de él. Otros comandos incorporados (que pueden tomar argumentos) no exhiben este tipo de comportamiento.
organizar el
@arrange La complicación es que el tiempo no permite un comando nulo (que habría desambiguado todo), solo permite una nueva línea en lugar del comando. Entonces, de time;datehecho, es sintácticamente incorrecto en cualquier interpretación. Sin embargo time ; y time ; ;luego también sería ilegal. Se puede debatir si timeel comportamiento es un error o simplemente no documentado ( es coherente internamente), pero un informe de error definitivamente estaría en su lugar. ¿Estarías dispuesto a archivarlo?
zwets
Bueno, miré la fuente (bash4.2: parse.y: lines 1205-1221) y allí dice eso time by itself can time a null commandy luego lo hace $$ = make_simple_command (x, (COMMAND *)NULL);. En cuanto a la presentación de un error, no estoy seguro 8)
organizar el
Cabe señalar que este problema es específico de bash. Hacer time ; datefunciona en ksh93y mkshsin errores, a pesar de que ksh hay una timepalabra clave.
Sergiy Kolodyazhnyy
2

Bash trata el incorporado timecomo un caso especial, al analizar líneas de comando.

Como se puede leer en la página de manual de bash, la línea escrita se divide primero en una lista:

pipeline ; pipeline

donde está una tubería:

[time [-p]] [ ! ] command [ [|⎪|&] command2 ... ]

o en nuestro caso, simplemente:

time command

es decir, si el tiempo está presente, entonces el comando también debe estar presente.

[Hay un caso especial que permite timeser seguido por una nueva línea, pero eso no se aplica aquí]

Entonces, en nuestro caso, tenemos:

time;date

dividido en dos tuberías:

1. time
2. date

y la tubería 1 no está bien formada, ya que tenemos timesin un comando. De ahí el error.

Tenga en cuenta que la línea de comandos timetampoco funciona aquí:

$ /usr/bin/time;date
Usage: /usr/bin/time [-apvV] [-f format] [-o file] [--append] [--verbose]

bash analiza esto como se esperaba, en 2 canales:

1. /usr/bin/time
2. date

y /usr/bin/timeluego se niega a correr sin argumento. Tenga en cuenta que este es un error de /usr/bin/timeno un error de bash.

La razón por la que funciona el retroceso es que el retroceso deja de timeser interpretado como un elemento especial dentro de la tubería.

es decir, con la marca de retroceso:

`time`;date

se analiza como dos tuberías:

1. `time`
2. date

Recuerde que una tubería, en nuestro caso, es:

[time] command

y el problema inicialmente fue que teníamos timesin comando, lo cual no está permitido Pero ahora simplemente tenemos el comando:

`time`

sin lo anterior time, ya que los ticks de retroceso significan que timese interpreta como el comando, no como una palabra anterior.

Entonces bash ejecuta su construcción timesin argumentos, lo cual es aceptado. No produce salida, y no vemos ningún error.

Tenga en cuenta que:

`time`

en realidad ejecuta el resultado del timeincorporado, es decir, ejecuta lo que el timeincorporado produce en stdout. Pero dado que timepor sí solo no escribe nada para stdout, parece funcionar.

Finalmente, se ha notado que esto funciona:

time ; ; date

que no puedo explicar, lamentablemente :)

cdmackay
fuente
Creo que tu explicación es mejor, pero todavía me parece extraño. ;dateda bash: syntax error near unexpected token ;, pero time ;dateda bash: syntax error near unexpected token date, por lo que parece que bash no trata el comando después del tiempo incorporado como "; fecha". Curiosamente, time ; ; datefunciona.
organizar el
sí, gracias @arrange, es bastante extraño. Actualizaré la respuesta un poco.
cdmackay
ok, @arrange, he reescrito. Sin embargo, todavía no puedo explicar tu último ... suspiro.
cdmackay
@cdmackay Estás mezclando backticks y citas. Al citar 'time' , pierde su significado como palabra reservada. Hacer retroceso lo hace ejecutar en una subshell cuya salida se empalma en el comando. Esto no tiene nada que ver con la discusión. De hecho, su ejemplo `time\';datedemuestra lo contrario de su reclamo: esto debería dar un error en su razonamiento porque /usr/bin/timerequiere un argumento. La razón por la que no lo hace es porque en la subshell en la que se ejecuta es la palabra reservada timeuna vez más.
zwets
@arrange Ambos son errores de sintaxis y se informa que ambos están cerca del mismo lugar, por lo que no veo una inconsistencia allí. Una vez que ingresa la tierra del error de sintaxis, no puede esperar que un analizador sepa su salida. Si necesita el de un analizador sintáctico, debe conocer no solo la sintaxis legal, sino también la sintaxis de cada posible construcción ilegal, lo cual es imposible por definición.
zwets