Perché la sequenza è importante nell'esecuzione di questi comandi bash?


10

Sembra esserci qualche incoerenza che non sono in grado di comprendere riguardo alla shell bash.

Se eseguo:

ls;date;time

i risultati delle tre query sono mostrati in sequenza.

Tuttavia, quando si scambiano la posizione di data e ora, viene visualizzato un messaggio di errore.

Quindi se eseguo:

ls;time;date

il messaggio di errore dice: bash: syntax error near unexpected token 'date'.

Qualcuno può spiegare questo?


Il tuo problema si trova su time;datevs date;time. Questo sembra essere un problema con la pipeline in bashe l'ultimo carattere generato con l' timeoutput. I risultati testati in diversi emulatori di terminale sono: - [Bash] $ date; time # [OK] $ time; date # [ NotOK ] bash: errore di sintassi vicino al token imprevisto `date '$ time # solo l'errore non sembra che sia il risultato di qualsiasi data. - [Csh] $ data; ora # [OK] $ ora; data # [OK] - [Tcsh] $ data; ora # [OK] $ ora; data # [OK] - [Ksh] $ data; ora # [ OK] $ ora; data # [OK]
Mostafa Shahverdy

Ho aggiornato la mia risposta con una spiegazione per il messaggio di errore. Verifica che questa sia la risposta che stavi cercando.
zwets

Risposte:


10

Il timecomando nella tua pipeline non è il /usr/bin/timebinario, ma il bash timeincorporato. Confronta man timecon help time. L'errore che vedi è che bash non riesce ad analizzare timel'argomento. Questo deve essere presente o essere una nuova riga. È una nuova riga nel tuo primo esempio ma assente nel secondo.

D'altra parte, se dovessi correre

ls;date;'time'

o

ls;'time';date

dove le virgolette 'time'revocano il suo stato di parola riservata, quindi bash non ha problemi ad analizzare la riga. Ora analizza tre comandi in un elenco, che eseguirà in sequenza e /usr/bin/timesegnalerà un errore di utilizzo in entrambi i casi.

appendice

È stato osservato che sebbene time ; dateproduca un errore, time ; ; datenon lo è. La probabile spiegazione è che time ;interpretata da bash come equivalente a time <newline>. L'espressione time ; ; dateviene quindi analizzata come l'elenco di time ;e date.

Ciò è coerente con l'osservazione che time ;e time ; ;sono anche legali, il secondo viene analizzato come elenco singleton contenente time ;seguito dal punto e virgola opzionale consentito dopo gli elenchi.

Quindi un altro modo di spiegare perché time ; dateproduce l'errore bash: syntax error near unexpected token 'date'è quello che timeconsuma il punto e virgola che lo separa date. Può farlo solo perché timeè una parola riservata bash.


Grazie per una bella spiegazione! Ma ancora una volta questo comportamento mi sembra un bug: timedovrebbe consentire un comando NULL e il punto e virgola dovrebbe delimitare gli elenchi, quindi il timecomando IMO non dovrebbe "consumare" il punto e virgola dopo di esso. Altri comandi integrati (che possono accettare argomenti) non mostrano questo tipo di comportamento.
organizzare l'

@arrange La complicazione è che il tempo non consente un comando nullo (che avrebbe chiarito tutto), consente solo una nuova riga al posto del comando. Quindi time;dateè davvero sintatticamente sbagliato in qualsiasi interpretazione. Tuttavia time ; e time ; ;sarebbe quindi anche illegale. Si può discutere se timeil comportamento sia un bug o semplicemente non documentato ( è internamente coerente), ma una segnalazione di bug sarebbe sicuramente in atto. Saresti disposto a archiviarlo?
zwets

Bene, ho guardato alla fonte (bash4.2: parse.y: righe 1205-1221) e lì lo dice time by itself can time a null commande poi lo fa $$ = make_simple_command (x, (COMMAND *)NULL);. Per quanto riguarda la presentazione di un bug non ne sono sicuro 8)
organizza il

Va notato che questo problema è specifico per Bash. Fare time ; datefunziona dentro ksh93e mkshsenza errori, anche se ksh c'è una timeparola chiave.
Sergiy Kolodyazhnyy il

2

Bash considera l'integrato timecome un caso speciale quando analizza le righe di comando.

Come si può leggere nella manpage di bash, la riga digitata viene prima suddivisa in un elenco:

pipeline ; pipeline

dove si trova una conduttura:

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

o nel nostro caso, semplicemente:

time command

cioè se il tempo è presente, allora deve essere presente anche il comando .

[Esiste un caso speciale che consente timedi essere seguito da una nuova riga, ma che non si applica qui]

Quindi, nel nostro caso, abbiamo:

time;date

essere diviso in due condotte:

1. time
2. date

e la pipeline 1 non è ben formata, poiché abbiamo timesenza un comando. Da qui l'errore.

Nota che la riga di comando timenon funziona neanche qui:

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

bash analizza questo come previsto, in 2 pipeline:

1. /usr/bin/time
2. date

e /usr/bin/timepoi si rifiuta di correre senza argomenti. Si noti che questo è un errore /usr/bin/timenon un errore di bash.

Il motivo per cui il back-tick funziona è che il back-tick smette di timeessere interpretato come un elemento speciale all'interno della pipeline.

cioè con il segno di spunta posteriore:

`time`;date

viene analizzato come due condutture:

1. `time`
2. date

Ricorda che una pipeline, nel nostro caso, è:

[time] command

e inizialmente il problema era che non avevamo timecomandi, il che non è permesso. Ma ora abbiamo semplicemente il comando:

`time`

senza il precedente time, poiché i segni di spunta indietro significano che timeviene interpretato come il comando, non come una parola precedente.

Quindi bash esegue il suo builtin timesenza argomenti, il che è accettato. Non produce output e non vediamo errori.

Nota che:

`time`

esegue effettivamente il risultato del timebuilt-in, ovvero esegue qualunque cosa il timebuilt-in produca su stdout. Ma poiché timeda solo non scrive nulla su stdout, sembra funzionare.

Infine, è stato notato che funziona:

time ; ; date

che non posso spiegare, purtroppo :)


Penso che la tua spiegazione sia migliore, ma mi sembra ancora strana. ;datebash: syntax error near unexpected token ;, ma time ;datebash: syntax error near unexpected token date, quindi sembra che bash non tratti il ​​comando dopo il tempo incorporato come "; data". È interessante notare che time ; ; datefunziona.
organizzare il

sì, grazie @arrange, è abbastanza strano. Aggiornerò leggermente la risposta.
cdmackay

ok, @arrange, hai riscritto. Non riesco ancora a spiegare il tuo ultimo sospiro ...
cdmackay

@cdmackay Stai mescolando backtick e virgolette. Con citando 'time' perde il suo significato di una parola riservata. Il backticking lo fa eseguire in una subshell il cui output viene unito al comando. Questo non ha nulla a che fare con la discussione. È un dato di fatto, il tuo esempio `time\';datedimostra il contrario della tua affermazione: questo dovrebbe dare un errore dal tuo ragionamento perché /usr/bin/timerichiede un argomento. Il motivo per cui non lo è è perché nella sottostruttura in cui viene eseguita è di nuovo la parola riservata time.
zwets

@arrange Entrambi sono errori di sintassi ed entrambi sono segnalato per essere vicino allo stesso posto, quindi non vedo una contraddizione lì. Una volta che entra nella terra dell'errore di sintassi, non puoi aspettarti che un parser sappia come uscire. Se richiedi quello di un parser, allora deve conoscere non solo la sintassi legale, ma anche la sintassi di ogni possibile costrutto illegale, il che è impossibile per definizione.
zwets
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.