Як саме працює "/ bin / ["?


50

Мене завжди дивує, що в папці /binє [програма.

Це те, що називається, коли ми робимо щось на кшталт if [ something ]:?

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

Потрібно сказати, що звичайний спосіб отримати допомогу щодо програми не працює, тобто не працює і man [не [ --helpпрацює.


11
@IporSircer [посилається на testкоманду, хоча, ні expr, так і має бутиman test
Сергій Колодяжний

8
man '['для мене добре працює - або ви забули процитувати, [або у вас є інше визначення поняття "твори".
Toby Speight

3
Кілька попереджень: [оцінює його аргументи, тому вам потрібно мати пробіли між усіма ними. [ a=b ]це не порівняння: воно завжди буде істинним (це єдина строка: "a = b", яка завжди оцінюється як істина ). А вам слід обмежити кількість аргументів на 4 (навіть якщо останні реалізації дозволять отримати більше. . Обмеження до 4 робить його більш портативним. Наприклад: [ "a" = "b" ]вже має 4 аргументи: "a" "=" "b" і не потрібний кінець тесту arg: "]"). Якщо вам потрібно більше: ланцюгові тести, наприклад:if [ "$Var_a" = "foo" ] && [ "$Var_b" = "bar" ] ; then : do something ; fi
Олів'є Дулак

1
@OlivierDulac a !сам по собі (без націски та без котирування) не буде замінено, а ще краще буде if ! [ .... Усі розгортання !
башів,

3
Слід також зазначити, що [в bash(і, можливо, інших оболонках) також є -буделін , і замість цього він може використовуватися /bin/[. Також є test-команда, яка в багатьох системах є символічним посиланням на /bin/[(або навпаки) - а на інших - окрема команда.
Баард Копперуд

Відповіді:


63

Завдання [команди - оцінити тестові вирази. Він повертається зі статусом виходу 0 (це означає істинний ), коли вираз дозволений до істинного, а в іншому (що означає помилкове ).

Справа не в тому, що вона нічого не робить, це просто результат її пошуку в статусі виходу. У оболонці ви можете дізнатись про стан виходу останньої команди в $?оболонках Борна або $statusв більшості інших оболонок (fish / rc / es / csh / tcsh ...).

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

На інших мовах, наприклад perl, статус виходу повертається, наприклад, у значення повернення system():

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

Зауважте, що всі сучасні оболонки Борна (і fish) мають вбудовану [команду. Типовий в /bin, як правило, виконується лише тоді, коли ви використовуєте іншу оболонку або коли ви робите такі речі, як env [ foo = bar ]або find . -exec [ -f {} ] \; -printта perlкоманда вище ...

[Команда також відома під testім'ям. При виклику як test, він не вимагає завершального ]аргументу.

Незважаючи на те, що у вашій системі може не бути довідної сторінки [, вона, ймовірно, має для неї test. Але ще раз зауважте, що це буде документувати /bin/[або /bin/testреалізовувати. Щоб знати про [вбудовану оболонку, слід замість цього прочитати документацію для оболонки.

Для отримання додаткової інформації про історію цієї утиліти та про різницю з [[...]]тестовим виразом ksh, ви можете ознайомитись з цим питанням Q&A тут .


Добре, як завжди. Ви можете додати коментарі, які я додав під питанням @Bregalad? а може, якісь зайві? Таким чином, відповідь буде ще більш повною на тему "як саме це працює" (зауважу, що ви вже дали більш точну інформацію про "]", ніж я ^^)
Олів'є Дулак

"Усі раковини, схожі на Борна (і риба), мають вбудовану [команду" Це правда на практиці в 21 столітті, але я впевнений, що без оболонки я використовував [. Я не пам'ятаю, чи це був варіант Борна чи антикварний варіант попелу.
Жиль "ТАК - перестань бути злим"

@Gilles Оболонка Bourne реалізована як [і testяк вбудовані з Unix System III. До цього не було [і testбула лише зовнішня бінарна команда.
jlliagre

@Gilles, оригінальний зола мав тест вбудований (злитий з expr), але необов'язково . За даними in-ulm.de/~mascheck/various/ash , BSD не мали вбудованих тестів приблизно до 2000 року. Я додав "сучасний".
Стефан Шазелас

Чому у світі ви хотіли б зробити find . -exec [ f {} ] \; -print? Команда find . -type f -printбуде робити те ж саме , так що набагато ефективніше ...
Це не моє справжнє ім'я

41

Мене завжди дивує, що в папці /binє [програма.

Ви праві здивовані. Це одна з рідкісних команд POSIX, з нульовою утилітою ( :), яка не відповідає файлу команд, дозволеному конвенції символів (набір символів портативного імені файлу).

Це те, що називається, коли ми робимо щось на кшталт if [ something ]:?

Точно, але його можна використовувати і без того if.

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

Він нічого не бачить, але насправді робить те саме, що і при використанні if, тобто встановлює статус виходу 0 (вірно) або що-небудь інше (помилкове) залежно від того, що ви ставите всередині дужок. Це (чомусь) та ж поведінка, що й testкоманда; Єдина відмінність полягає в тому, що він шукає закінчення ]. Детальніше man testдив.

Потрібно сказати, що звичайний спосіб отримати допомогу щодо програми не працює, тобто не працює і man [не [ --helpпрацює.

Це залежить від вашої операційної системи. man [Однозначно працює для мене в кількох дистрибутивах Gnu / Linux, але це не на Solaris.

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

Усі сучасні інтерпретатори оболонок у стилі Борна (як bash, наприклад ksh, dashі, zshщоб назвати їх декілька) впроваджують test/ [утиліту внутрішньо як вбудований, тому, коли ви користуєтесь ними, правою сторінкою для посилань може бути саме оболонка, а не testодна.

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

if test something ; then

замість:

if [ something ] ; then


"man (безумовно, працює для мене в основних дистрибутивах Gnu / Linux" Хм .. Centos (правда, 6,8 все ще) явно недостатньо мейнстріму :) man testпрацює, але ні. man [ З іншого боку, моє середовище cygwin знає про man [!
Адам

1
@Adam Так, ви маєте рацію, це нещодавніше, ніж я думав, хоча я не написав усіх основних Linux-дистрибутивів, тільки що він працював на мене (тобто на ті, які я тестував). Це клон OL 7.2 (RHEL 7.2) та монетний двір 17.1 (Ubuntu 14.04).
jlliagre

man [не працює на Manjaro (на базі Arch Linux). Посібник для testсписків [ --helpяк дійсного виклику, який повинен містити допомогу, але що цікаво, це не так, а натомість скаржиться на відсутність ], як і у випадку з --version. Додавання ]нічого не робить, тому, здається, неможливо отримати допомогу, окрім як man test.
Darkhogg

@Darkhogg Ви можете спробувати /usr/bin/[ --helpабо /bin/[ --help.
jlliagre

1
@jlliagre Ви абсолютно праві, я використовував вбудовані. env [ --helpа також /usr/bin/[ --helpпрацювати повністю чудово (хоча мені потрібно цитувати /usr/bin/[або zsh скаржитися).
Darkhogg

10

[насправді більш відомий як testкоманда. Типовим використанням цієї команди є просто оцінка виразів та повернення їх стану - істинного чи хибного. Він часто використовується в if-then-else-fiоператорах, хоча він може використовуватися поза ifоператорами, щоб умовно запускати інші команди через оболонки &&або ||оператори, як так.

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

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

Більш конкретно, оцінка повідомляється іншим командам через статус виходу. Деякі програми можуть вибрати статус виходу для позначення різних типів подій - програма успішно завершується, помилка певного типу, що виникає під час виконання, або синтаксичні помилки. У випадку testкоманди є 0позначення true, а 1означає false. Як зазначив Стефан, синтаксичні помилки створюють статус виходу 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). Що стосується інших (наприклад, Arch), це не так. (Але testдовідкова сторінка також використовує документи [)


type -a [ показує, що є вбудована оболонка і виконуваний файл.

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

bash-вбудований [ --helpпросто друкує повідомлення про помилку. (Але оскільки це вбудований, ви можете використовувати help [або переглядати сторінку / документи bash man).

/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рівнозначні.


BTW, якщо ви програмуєте для 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:" $?

… Виведе:

Вихід-статус [привіт] становить: 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аргументів може привести до збою з повідомленням про помилку або повернути неправильний результат) . І може вирішити той же файл (наприклад , один слінкован , в цьому випадку поведінка витік, ймовірно , реалізується шляхом аналізу в даний час званої команди в / сам коді) або до різних файлів. Бо , оболонка також зазвичай викликає вбудований сурогат, якщо шлях прямо не вказано ( ) або він налаштований не робити цього (/bin/test/bin/[test[test/bin/testenable -n test).

PPS: В відміну від testі [сучасний ifніколи не реальний файл. Це частина синтаксису оболонки (наприклад, bash): if commandA; then commandB; fi(нові рядки можуть використовуватися замість крапки з комою) призводить commandBдо того, що він виконується "if-and-only", якщо 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командою.
Стефан Шазелас
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.