Как именно работает «/ bin / [»?

50

Я всегда удивляюсь, что в папке /binесть [программа.

Это то , что называется , когда мы делаем что - то вроде: if [ something ]?

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

Излишне говорить, что обычный способ получения справки о программе не работает, то есть ни работает, man [ни [ --helpработает.

Bregalad
источник
11
@IporSircer [относится к testкоманде, хотя, нет expr, так и должно бытьman test
Сергей Колодяжный
8
man '['у меня работает нормально - либо вы забыли процитировать, [либо у вас другое определение "работы".
Тоби Спейт
3
Несколько предупреждений: [оценивает его аргументы, поэтому вам нужно иметь пробелы между ними. [ a=b ]это не сравнение: это всегда будет true (это одна строка: «a = b», которая всегда оценивается как true ). И вам следует ограничить число аргументов до 4 (даже если недавние реализации позволят больше .. Ограничение до 4 делает его более переносимым. Например: [ "a" = "b" ]уже имеет 4 аргумента: "a" "=" "b" и необязательный конец теста arg: "]"). Если вам нужно больше: цепные тесты, например:if [ "$Var_a" = "foo" ] && [ "$Var_b" = "bar" ] ; then : do something ; fi
Оливье Дюлак
1
@OlivierDulac a !сам по себе (без экранирования и без кавычек) не будет заменен, а еще лучше if ! [ .... Все расширения bash, которые используют, !включают как минимум другого персонажа
muru
3
Вы также должны заметить, что [в bash(и, возможно, в других оболочках) также есть -буилтин , и что он может быть использован вместо /bin/[. Также есть команда test-com, которая во многих системах является символической ссылкой /bin/[(или наоборот), а в других - отдельной командой.
Baard Kopperud

Ответы:

63

Работа [команды заключается в оценке тестовых выражений. Возвращается со статусом выхода 0 (что означает true ), когда выражение разрешается в true, а в противном случае (что означает false ) в противном случае.

Дело не в том, что он ничего не делает, просто его результат находится в статусе выхода. В оболочке вы можете узнать о состоянии завершения последней команды $?для оболочек типа Борна или $statusбольшинства других оболочек (fish / rc / es / csh / tcsh ...).

$ [ a = a ]
$ echo "$?"
0
$ [ a = b ]
$ echo "$?"
1

В других языках, например perl, статус выхода возвращается, например, в возвращаемом значении system():

$ perl -le 'print system("[", "a", "=", "a", "]")'
0

Обратите внимание, что все современные Bourne-подобные оболочки (и fish) имеют встроенную [команду. Один в /binобычно выполняются только тогда , когда вы используете другую оболочку или когда вы делаете что - то вроде env [ foo = bar ]или find . -exec [ -f {} ] \; -printили что perlкоманды выше ...

Команда [также известна под testименем. Когда testвызывается как , он не требует закрывающего ]аргумента.

Хотя ваша система может не иметь справочную страницу для [, она, вероятно, есть для test. Но опять же, обратите внимание, что это будет документировать /bin/[или /bin/testреализацию. Чтобы узнать о [встроенной функции в вашей оболочке, вам следует прочитать документацию по вашей оболочке.

Для получения дополнительной информации об истории этой утилиты и разнице с [[...]]тестовым выражением ksh вы можете посмотреть здесь другие вопросы и ответы .

Стефан Шазелас
источник
Хорошо, как обычно. Возможно, вы захотите добавить комментарии, которые я добавил под вопросом @Bregalad? или, может быть, какие-то дополнительные? Таким образом, ответ будет еще более полным о том, «как именно это работает» (отмечу, что вы уже дали более точную информацию о «]», чем я ^^)
Оливье Дюлак
«У всех похожих на Борн оболочек (и рыб) есть встроенная команда. Это верно на практике в 21-м веке, но я уверен, что использовал оболочку без [. Я не помню, был ли это вариант Борна или античная версия пепла.
Жиль "ТАК - перестань быть злым"
@Gilles Оболочка Bourne реализована в Unix System III [и реализована в testвиде встроенных компонентов . До этого не было [и testбыло только внешней двоичной команды.
Jlliagre
@ Жиль, у исходного пепла был встроенный тест (объединенный с expr), но по желанию . Согласно in-ulm.de/~mascheck/various/ash , BSD не имели встроенных тестов примерно до 2000 года. Я добавил «современный».
Стефан
Почему в мире вы хотели бы сделать find . -exec [ f {} ] \; -print? Команда find . -type f -printбудет делать то же самое , так что гораздо более эффективно ...
Это не мое настоящее имя
41

Я всегда удивляюсь, что в папке /binесть [программа.

Вы правильно удивлены. Это одна из редких команд POSIX с утилитой null ( :), которая не соблюдает соглашение о допустимых символах командного файла (набор символов переносимого имени файла).

Является ли это то , что называется , когда мы делаем что - то вроде: if [ something ]?

Точно, но это может использоваться без ifслишком.

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

Он ничего не делает видимым, но на самом деле он делает то же самое, что и при использовании с ним if, то есть он устанавливает состояние выхода на 0 (true) или что-либо еще (false) в зависимости от того, что вы заключили в скобки. Это (по причине) такое же поведение, как testкоманда; единственная разница в том, что он ищет концовку ]. Смотрите man testподробности.

Излишне говорить, что обычный способ получения справки о программе не работает, то есть ни работает, man [ни [ --helpработает.

Это зависит от вашей операционной системы. man [определенно работает для меня в нескольких основных дистрибутивах Gnu / Linux, но не в Solaris.

[ --helpможет работать или не работать в зависимости от реализации, так как в любом случае нарушает синтаксис, пропуская окончание ]. Кроме того, стандарт POSIX для test/ [команды явно исключает все возможные варианты, в том числе --прекращение вариант так как [ --help ]и test --helpнеобходимости возвращения trueи молчать дизайн. Обратите внимание, что вы положили в скобках или после того, как [и что выглядят как варианты (например -f file, -n stringи подобные) не являются варианты , но операнды .

Все современные Bourne интерпретаторы стиль оболочки (как bash, ksh, dashи zshнекоторые из них) реализации test/ [утилиты внутри как встроенная , так когда вы используете их, страница право руководство для обозначения может быть одна из оболочки, а не testодин.

До Unix System III (1981) оболочка Bourne не реализовывала testутилиту как встроенную, поэтому была доступна только реализация внешних двоичных команд. До [Unix System III не было ни команды (внутренней или встроенной), поэтому, например, в Unix версии 7 вы должны были набрать:

if test something ; then

вместо:

if [ something ] ; then
jlliagre
источник
"Человек [определенно работает для меня в распространенных дистрибутивах Gnu / Linux" Хмм .. Centos (по-прежнему 6.8) явно недостаточно для мейнстрима :) man testработает, но нет man [ С другой стороны, моя среда cygwin знает об этом man [!
Адам
1
@ Adam Да, вы правы, это более недавно, чем я думал, хотя я не писал все основные дистрибутивы Linux, просто он работал для меня (то есть на тех, которые я тестировал). Это клон OL 7.2 (RHEL 7.2) и Mint 17.1 (Ubuntu 14.04).
jlliagre
man [похоже, не работает на Manjaro (Arch Linux на основе). Руководство для testсписков [ --helpв качестве действительного вызова, которое должно показывать помощь, но, что интересно, это не так, и вместо этого жалуется на отсутствие ], так же, как и с --version. Добавление ]ничего не делает, поэтому кажется невозможным получить помощь, кроме как от man test.
Darkhogg
@ Darchogg Вы можете попробовать /usr/bin/[ --helpили /bin/[ --help.
Jlliagre
1
@jlliagre Вы совершенно правы, я использовал встроенные функции. env [ --helpа также /usr/bin/[ --helpработает совершенно нормально (хотя мне нужно цитировать /usr/bin/[или жш жалуется).
Darkhogg
10

[на самом деле более широко известен как testкоманда. Типичное использование этой команды - просто оценить выражения и вернуть их условие - true или false. Он часто используется в if-then-else-fiоператорах, хотя он может использоваться вне ifоператоров для условного запуска других команд через оболочки &&или ||операторы, например, так.

$ [ -e /etc/passwd  ] && echo "File exists"
File exists

$ test -e /etc/passwd && echo "File exists"
File exists

Более конкретно, оценка передается другим командам через состояние выхода. Некоторые программы могут выбрать вывод состояния выхода для обозначения различных типов событий - программа успешно завершена, ошибка определенного типа, возникающая во время выполнения, или синтаксические ошибки. В случае testкоманды есть 0означает истину и 1означает ложь. Как указал Стефан, синтаксические ошибки приводят к состоянию выхода 2.

Его местоположение зависит от вашей системы, и это также объясняет, почему вы не видели страницу руководства, когда вы это сделали man [. Например, на FreeBSD он находится под /bin. В Linux (или в моем конкретном случае, Ubuntu 16.04) он находится в /usr/bin/. Если вы это делаете man [или man testработаете в системе Linux, вы увидите ту же документацию открытой. Также важно отметить, что ваша оболочка может иметь собственную реализацию test.

Следует также отметить, что у этой команды есть проблемы , которые пытается решить реализация оболочки Korn (обычно называемая ссылкой «условное выражение» в двойных квадратных скобках [[ "$USER" = "root" ]]). Эта функция также используется другими оболочками, такими как bashи zsh.

Сергей Колодяжный
источник
/usr/bin/для Amazon Linux также.
franklinsijo
@ StéphaneChazelas Спасибо. Ответ отредактировал соответственно
Сергей Колодяжный
3

Ни , man [ни [ --helpработы

В некоторых дистрибутивах (например, Ubuntu) man [следует символическая ссылка на test(1). На других (например, Арка) это не так. (Но testстраница руководства [также документирует использование )


type -a [ показывает, что есть встроенная оболочка и исполняемый файл.

$ type -a [
[ is a shell builtin
[ is /usr/bin/[

bash-builtin [ --helpпросто печатает сообщение об ошибке. (Но так как это встроенная версия, вы можете использовать ее help [или просмотреть страницу руководства / документацию по bash).

/usr/bin/[ --help выводит полный вывод справки (для версии GNU Coreutils), который начинается с:

$ /usr/bin/[ --help
Usage: test EXPRESSION
  or:  test
  or:  [ EXPRESSION ]
  or:  [ ]
  or:  [ OPTION
Exit with the status determined by EXPRESSION.

      --help     display this help and exit
      --version  output version information and exit

а затем описывает допустимый синтаксис для EXPRESSION.

Это еще один способ, которым вы могли бы узнать это [и testэквивалентны.


Кстати, если вы программируете для bash (или пишете однострочно в интерактивном режиме), я бы порекомендовал [[вместо [. Это лучше несколькими способами, см. Ссылки в ответе Серга.

Питер Кордес
источник
2

[команда возвращает нулевое состояние выхода, если выражение, содержащееся в ее аргументах, считается истинным, а ненулевое состояние выхода, если выражение, содержащееся в его аргументах, считается ложным. Он также завершается с сообщением об ошибке, если его последний аргумент не является ](это делается исключительно по эстетическим соображениям).

Например:

[ hello ]
echo "Exit-status of [ hello ] is:" $?
[ abc = abc ]
echo "Exit-status of [ abc = abc ] is:" $?
[ ]
echo "Exit-status of [ ] is:" $?
[ abc = def ]
echo "Exit-status of [ abc = def ] is:" $?

… Выведет:

Состояние выхода [hello] равно: 0       - потому что непустая строка считается истинной 
Состояние выхода [abc = abc] равно: 0   - потому что 'abc' действительно совпадает с 'abc' 
Состояние выхода [] : 1             - потому что пустая строка считается ложной. 
Статус выхода [abc = def]: 1   - потому что 'abc' действительно отличается от 'def'

Однако bash и многие другие оболочки обычно не вызывают /bin/[(или /usr/bin/[) в этих случаях, а вместо этого вызывают встроенную команду с точно таким же поведением (исключительно по соображениям производительности). Для вызова /bin/[(не суррогата встроенной в оболочку) вам необходимо либо явно указать его путь (например /bin/[ hello ], вам не нужно] указывать префикс dirname, хотя, ), либо настроить оболочку, чтобы она не использовала встроенную суррогатную (например, enable -n [в баш).

PS: Как было сказано в других ответах, [связано с test. Но test, в отличие от этого [, не требует в ]качестве последнего аргумента (и вообще не ожидает его; добавление дополнительных ]к testаргументам может привести к сбою с сообщением об ошибке или к возвращению неверного результата) . И может решить тот же файл (например , один слинкован , в этом случае поведение утечка, вероятно , реализуется путем анализа в настоящее время называемой команды в / сам коде) или к различным файлам. Для , shell также обычно вызывает встроенный суррогат, если путь явно не указан ( ) или не настроен на это (/bin/test/bin/[test[test/bin/testenable -n test).

PPS: В отличие от testи [, современное ifникогда не бывает настоящим файлом. Он является частью синтаксиса оболочки (например, bash): if commandA; then commandB; fi(вместо точек с запятой можно использовать символы новой строки), commandBесли он выполняется, если он и только при commandAвыходе, с нулевым статусом. Это идеально соответствует поведению testили [, позволяя объединять их как if [ "$a" = foo ]; then …; fi (или if test "$a" = foo; then …; fi- просто менее читабельно) . Однако современные сценарии часто используют [[вместо testили [, что (как if) никогда не является реальным файлом, но всегда является частью синтаксиса оболочки.

PPPS: Что касается man- никогда не ждите manстатьи по каждой команде в вашей файловой системе. Информация о какой - то (даже «реального», на основе файлов) команды могут отсутствовать информация о некоторых оболочечных встроенных модулей может быть , присутствует не только в статье , посвященной конкретной оболочки (это место , где вы наверняка найдете информацию о test, [, if, [[). Тем не менее, во многих дистрибутивах есть явные manстатьи для testи [. (О --help, это не распознается testпо очевидной причине: он должен спокойно обрабатывать такие случаи, как a=--help; test "$a"; в некоторых дистрибутивах [ --help(без закрытия ]) по-прежнему показывает помощь, в некоторых - нет).

саша
источник
3
Обратите внимание, что это ifбыла команда до Unix V6. Unix V7 (1979) поставляется с оболочкой Bourne (с ее if-then-else-fiконструкцией) и новой testкомандой.
Стефан