Dlaczego sekwencja ma znaczenie przy wykonywaniu tych poleceń bash?

10

Wydaje się, że istnieje pewna niespójność, której nie jestem w stanie zrozumieć odnośnie powłoki bash.

Jeśli wykonam:

ls;date;time

wyniki trzech zapytań są pokazane kolejno.

Jednak przy zmianie pozycji daty i godziny pojawia się komunikat o błędzie.

Więc jeśli wykonam:

ls;time;date

komunikat o błędzie mówi: bash: syntax error near unexpected token 'date'.

Czy ktoś może to wyjaśnić?

rohitvijaysharma
źródło
Twój problem leży na time;dateżywo date;time. Wydaje się, że jest to problem z wejściem do potoku bashi ostatnim char generowanym z timewyjściem. Testowane wyniki w różnych emulatorach terminali to: - [Bash] $ data; godzina # [OK] $ godzina; data # [ NotOK ] bash: błąd składni w pobliżu nieoczekiwanego tokena `data '$ czas # tylko błąd nie pojawia się, że jest to wynik dowolnej daty. - [Csh] $ data; godzina # [OK] $ godzina; data # [OK] - [Tcsh] $ data; godzina # [OK] $ godzina; data # [OK] - [Ksh] $ data; godzina # [ OK] $ godzina; data # [OK]
Mostafa Shahverdy
Zaktualizowałem odpowiedź, wyjaśniając komunikat o błędzie. Sprawdź, czy to odpowiedź, której szukasz.
zwets

Odpowiedzi:

10

timeKomenda w rurociągu nie jest /usr/bin/timebinarny, ale bash timewbudowanej. Porównaj man timez help time. Widoczny błąd polega na tym, że bash nie analizuje timeargumentu. To musi być obecne lub być nowym wierszem. Jest to nowy wiersz w twoim pierwszym przykładzie, ale nieobecny w drugim.

Z drugiej strony, jeśli miałbyś biec

ls;date;'time'

lub

ls;'time';date

gdzie cytaty wokół 'time'odwołują swój status słowa zarezerwowanego, wtedy bash nie ma problemów z analizą wiersza. Teraz analizuje trzy polecenia na liście, które wykona kolejno i /usr/bin/timew obu przypadkach zgłosi błąd użycia.

Uzupełnienie

Zaobserwowano, że chociaż time ; datedaje błąd, time ; ; datenie robi. Prawdopodobnym wyjaśnieniem jest to, że time ;interpretacja bash jest równoznaczna z time <newline>. Wyrażenie time ; ; datejest następnie analizowane jako lista time ;i date.

Jest to zgodne z obserwacją, że time ;i time ; ;są zgodne z prawem, a także, druga jest analizowany jako listy jednoelementowy zawieraj time ;następnie opcjonalnego średnikiem dozwolony po listach.

Tak więc innym sposobem wyjaśnienia, dlaczego pojawia się time ; datebłąd, bash: syntax error near unexpected token 'date'jest to, że timezużywa go średnik oddzielający go date. Może to zrobić tylko dlatego, że timejest zarezerwowanym słowem bash.

zwets
źródło
Dzięki za miłe wyjaśnienie! Ale znowu to zachowanie wydaje mi się błędem: timepowinno pozwalać na polecenie NULL, a średnik ma ograniczać listy, więc timepolecenie IMO nie powinno „zużywać” średnika po nim. Inne wbudowane polecenia (które mogą przyjmować argumenty) nie wykazują tego rodzaju zachowania.
umówić
@arrange Powikłanie to, że czas nie pozwala komenda zerowa (to musiałby ujednoznacznione wszystko), pozwala jedynie przełamane zamiast polecenia. Tak time;datejest w istocie składniowo źle w dowolnej interpretacji. Jednak time ; i time ; ;wtedy też byłoby nielegalne. Można dyskutować, czy timezachowanie jest błędem, czy tylko nieudokumentowanym ( jest wewnętrznie spójny), ale raport o błędzie na pewno będzie na miejscu. Czy byłbyś skłonny to złożyć?
zwets
Cóż, spojrzałem na źródło (bash4.2: parse.y: linie 1205-1221) i tam to mówi, time by itself can time a null commanda potem robi to przez $$ = make_simple_command (x, (COMMAND *)NULL);. Jeśli chodzi o zgłaszanie błędu, nie jestem pewien 8)
umów się na
Należy zauważyć, że ten problem jest specyficzny dla bash. Robi time ; dateprace w ksh93i mkshbez błędów, choć w ksh nie timesłów kluczowych.
Sergiy Kolodyazhnyy
2

Bash traktuje wbudowany timeelement jako specjalny przypadek podczas analizowania linii poleceń.

Jak można przeczytać na stronie podręcznika bash, wpisany wiersz jest najpierw dzielony na listę:

pipeline ; pipeline

gdzie rurociąg jest:

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

lub w naszym przypadku po prostu:

time command

tzn. jeśli czas jest obecny, polecenie musi być również obecne.

[Istnieje szczególny przypadek, który pozwala timena dodanie nowej linii, ale nie dotyczy to tutaj]

W naszym przypadku mamy:

time;date

podzielony na dwa rurociągi:

1. time
2. date

a rurociąg 1 nie jest dobrze uformowany, ponieważ mamy timebez polecenia. Stąd błąd.

Zauważ, że timetutaj również nie działa wiersz poleceń :

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

bash analizuje to zgodnie z oczekiwaniami, w 2 potoki:

1. /usr/bin/time
2. date

a /usr/bin/timenastępnie odmawia uruchomienia bez argumentów. Zauważ, że jest to błąd wynikający z /usr/bin/timebłędu bash.

Powodem, dla którego działa tykanie wstecz jest to, że tykanie przestaje timebyć interpretowane jako specjalny element w potoku.

tj. z tyknięciem wstecz:

`time`;date

jest analizowany jako dwa potoki:

1. `time`
2. date

Pamiętaj, że rurociąg w naszym przypadku to:

[time] command

a problem początkowo polegał na tym, że nie mieliśmy timepolecenia, co jest niedozwolone. Ale teraz mamy po prostu polecenie:

`time`

bez poprzedzającego time, ponieważ znaczniki cofania oznaczają, że timejest interpretowane jako polecenie, a nie jako poprzedzające słowo.

Więc bash następnie uruchamia swoją wbudowaną wersję timebez argumentów, co jest akceptowane. Nie wytwarza danych wyjściowych i nie widzimy błędów.

Uwaga:

`time`

faktycznie prowadzi wynik z następujących timewbudowany, czyli działa bez względu na timewbudowaną produkuje na standardowe wyjście. Ale ponieważ timesam nie pisze niczego na standardowe wyjście, wydaje się, że działa.

Wreszcie zauważono, że to działa:

time ; ; date

czego niestety nie potrafię wyjaśnić :)

cdmackay
źródło
Myślę, że twoje wyjaśnienie jest lepsze, ale nadal wydaje mi się dziwne. ;datedaje bash: syntax error near unexpected token ;, ale time ;datedaje bash: syntax error near unexpected token date, więc wydaje się, że bash nie traktuje polecenia po wbudowanym czasie jako „; data”. Co ciekawe, time ; ; datedziała.
umówić
tak, dzięki @arrange, to dość dziwne. Lekko zaktualizuję odpowiedź.
cdmackay,
ok, @arrange, przepisałem. Nadal nie mogę wyjaśnić twojego ostatniego ... westchnienia.
cdmackay,
@cdmackay Mieszasz zwrotki i cytaty. Przez cytowanie 'time' traci swoje znaczenie jako zarezerwowanego słowa. Ponowne kliknięcie powoduje wykonanie go w podpowłoce, której dane wyjściowe są łączone w komendzie. To nie ma nic wspólnego z dyskusją. W rzeczywistości twój przykład `time\';datejest sprzeczny z twoim twierdzeniem: powinno to prowadzić do błędu w twoim rozumowaniu, ponieważ /usr/bin/timewymaga argumentu. Powodem tego nie jest, ponieważ w podpowłoce, w której się wykonuje, jest to słowo zastrzeżone time.
zwets
@arrange Oba są błędami składniowymi i oba zgłaszane są w pobliżu tego samego miejsca, więc nie widzę tam niekonsekwencji. Po wejściu w obszar błędów składniowych nie można oczekiwać, że analizator składni pozna wyjście. Jeśli potrzebujesz parsera, musi on znać nie tylko składnię prawną, ale także składnię każdej możliwej nielegalnej konstrukcji, co z definicji jest niemożliwe.
zwets