Почему последовательность имеет значение при выполнении этих команд bash?

10

Кажется, есть некоторая несогласованность, которую я не могу понять в отношении оболочки bash.

Если я выполню:

ls;date;time

Результаты трех запросов показаны в последовательности.

Однако при смене даты и времени всплывает сообщение об ошибке.

Итак, если я выполню:

ls;time;date

сообщение об ошибке говорит: bash: syntax error near unexpected token 'date'.

Может кто-нибудь объяснить это?

rohitvijaysharma
источник
Ваша проблема лежит time;dateпротив date;time. Это, похоже, проблема с конвейером bashи последним символом, сгенерированным с timeвыходом. Результаты тестирования в различных эмуляторах терминала: - [Bash] $ date; time # [OK] $ time; date # [ NotOK ] bash: синтаксическая ошибка рядом с неожиданным токеном `date '$ time # только ошибка не появляется, что это результат любой даты. - [Csh] $ date; время # [OK] $ время; date # [OK] - [Tcsh] $ date; время # [OK] $ время; date # [OK] - [Ksh] $ date; время # [ OK] $ time; дата # [OK]
Мостафа Шахверди
Я обновил свой ответ объяснением для сообщения об ошибке. Пожалуйста, проверьте, что это ответ, который вы искали.
zwets

Ответы:

10

Команда timeв вашем конвейере не /usr/bin/timeдвоичная, а timeвстроенная в bash . Сравните man timeс help time. Ошибка, которую вы видите, это то, что bash не может разобрать timeаргумент. Это должно или присутствовать или быть новой строкой. Это новая строка в вашем первом примере, но отсутствует во втором.

С другой стороны, если вы должны были бежать

ls;date;'time'

или

ls;'time';date

где кавычки 'time'аннулируют его статус зарезервированного слова, тогда bash без проблем разбирает строку. Теперь он анализирует три команды в списке, которые он будет выполнять последовательно, и /usr/bin/timeсообщит об ошибке использования в любом случае.

добавление

Было отмечено, что, хотя и time ; dateдает ошибку, time ; ; dateнет. Вероятное объяснение состоит в том, что time ;bash интерпретируется как эквивалентное time <newline>. Затем выражение time ; ; dateанализируется как список time ;и date.

Это согласуется с наблюдением , что time ;и time ; ;являются законными , а также, второе существо обрабатываются как список одноплодного , содержащие time ;затем необязательной точка с запятой после списка.

Итак, еще один способ объяснить, почему time ; dateвыдает ошибку, bash: syntax error near unexpected token 'date'состоит в том, что она timeиспользует точку с запятой, отделяющую ее от date. Это может быть сделано только потому, что timeэто зарезервированное слово bash.

zwets
источник
Спасибо за приятное объяснение! Но с другой стороны, это поведение выглядит для меня как ошибка: timeпредполагается, что команда NULL допускается, а точка с запятой должна разделять списки, поэтому IMO timeкоманда не должна «использовать» точку с запятой после нее. Другие встроенные команды (которые могут принимать аргументы) не демонстрируют такого рода поведение.
организовать
@arrange Сложности заключается в том , что время не позволяет команде нуля (что бы многозначное все), это позволяет только символ новой строки вместо команды. Так что time;dateэто действительно синтаксически неправильно в любой интерпретации. Однако time ; и time ; ;тогда тоже будет незаконным. Можно спорить ли timeповедение «S является ошибкой или просто без документов (она является внутренне непротиворечивой), но сообщение об ошибке, несомненно , будет на месте. Вы хотели бы подать это?
zwets
Ну, я посмотрел на источник (bash4.2: parse.y: линии 1205-1221), и там он говорит, что time by itself can time a null commandи затем он делает это $$ = make_simple_command (x, (COMMAND *)NULL);. Что касается регистрации ошибки, я не уверен, 8)
организовать
Следует отметить, что эта проблема связана с Bash. Выполнение time ; dateработ в ksh93и mkshбез каких - либо ошибок, даже если в ksh есть timeключевое слово.
Сергей Колодяжный
2

Bash рассматривает встроенное timeкак особый случай при разборе командных строк.

Как можно прочитать на man-странице bash, набранная строка сначала разбивается на список:

pipeline ; pipeline

где трубопровод:

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

или в нашем случае просто:

time command

т.е. если время присутствует, то команда должна также присутствовать.

[Существует особый случай, который позволяет timeследовать за новой строкой, но это не относится здесь]

Итак, в нашем случае мы имеем:

time;date

разделяется на два трубопровода:

1. time
2. date

и конвейер 1 не очень хорошо сформирован, так как у нас timeбез команды. Отсюда и ошибка.

Обратите внимание, что командная строка timeздесь тоже не работает:

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

bash разбирает это, как и ожидалось, на 2 конвейера:

1. /usr/bin/time
2. date

а /usr/bin/timeзатем отказывается бежать без аргументов. Обратите внимание, что это ошибка, а /usr/bin/timeне ошибка bash.

Причина, по которой обратная галочка работает, заключается в том, что обратная галочка перестает timeинтерпретироваться как специальный элемент в конвейере.

то есть с обратной галочкой:

`time`;date

он разбирается как два конвейера:

1. `time`
2. date

Помните, что конвейер в нашем случае это:

[time] command

и проблема изначально заключалась в том, что у нас не timeбыло команды, что запрещено. Но теперь у нас просто есть команда:

`time`

без предшествующего time, поскольку обратные галочки означают, что timeинтерпретируется как команда, а не как предыдущее слово.

Таким образом, bash запускает свою встроенную систему timeбез аргументов, что принимается. Он не производит вывод, и мы не видим ошибки.

Обратите внимание, что:

`time`

фактически запускает результат из timeвстроенной, то есть он работает независимо от timeвстроенного производит на стандартный вывод. Но поскольку сам timeпо себе ничего не пишет в stdout, похоже, он работает.

Наконец, было отмечено, что это работает:

time ; ; date

что я не могу объяснить, к сожалению :)

cdmackay
источник
Я думаю, что ваше объяснение лучше, но оно все еще выглядит странно для меня. ;dateдает bash: syntax error near unexpected token ;, но time ;dateдает bash: syntax error near unexpected token date, поэтому кажется, что bash не обрабатывает команду после встроенного времени как "; date". Интересно, time ; ; dateработает.
устроить
да, спасибо @arrange, это довольно странно. Я немного обновлю ответ.
cdmackay
хорошо, @arrange, переписал. Тем не менее, не могу объяснить ваш последний хотя ... вздох.
cdmackay
@cdmackay Вы смешиваете кавычки и кавычки. По процитировать 'time' она теряет свое значение как зарезервированное слово. Откат назад заставляет его выполняться в подоболочке, чей вывод включается в команду. Это не имеет ничего общего с обсуждением. Фактически, ваш пример `time\';dateдоказывает противоположность вашего утверждения: это должно привести к ошибке по вашим рассуждениям, потому что /usr/bin/timeтребует аргумента. Причина этого заключается в том, что в подоболочке, в которой он выполняется, это timeснова зарезервированное слово .
zwets
@arrange Обе ошибки являются синтаксическими, и, как сообщается, они находятся примерно в одном и том же месте, поэтому я не вижу там несоответствия. Как только он входит в землю с синтаксической ошибкой, вы не можете ожидать, что парсер узнает его выход. Если вам потребуется синтаксический анализатор, он должен знать не только допустимый синтаксис, но и синтаксис всех возможных недопустимых конструкций, что невозможно по определению.
zwets