Почему “ `встроенная оболочка и` [[`ключевое слово оболочки?

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

 [root@server ~]# type [ [ is a shell builtin [root@server ~]# type [[ [[ is a shell keyword 

TLDP говорит

Встроенный может быть синонимом системной команды с тем же именем, но Bash повторно ее реализует. Например, команда echo Bash не совпадает с / bin / echo, хотя их поведение почти идентично.

а также

Ключевое слово – зарезервированное слово, токен или оператор. Ключевые слова имеют особое значение для оболочки и действительно являются строительными блоками синтаксиса оболочки. В качестве примеров, для, while, do, and! это ключевые слова. Подобно встроенному, ключевое слово жестко закодировано в Bash, но, в отличие от встроенного, ключевое слово само по себе не является командой, а является подразделением командной строки. [2]

Разве это не должно быть как [ и [[ ключевое слово? Есть что-то, чего я здесь не хватает? Кроме того, эта ссылка подтверждает, что оба [ и [[ должны принадлежать одному и тому же типу.

4 Solutions collect form web for “Почему “ `встроенная оболочка и` [[`ключевое слово оболочки?”

Различие между [ и [[ является весьма фундаментальным.

  • [ это команда. Его аргументы обрабатываются так, как обрабатываются любые другие аргументы команд. Например, рассмотрим:

     [ -z $name ] 

    Оболочка будет расширять $name и выполнять как разбиение слов, так и генерация имени файла на результат, как и для любой другой команды.

    В качестве примера выполните следующие действия:

     $ name="here and there" $ [ -n $name ] && echo not empty bash: [: too many arguments 

    Чтобы эта работа была правильной, необходимы котировки:

     $ [ -n "$name" ] && echo not empty not empty 
  • [[ является ключевым словом оболочки, и его аргументы обрабатываются в соответствии со специальными правилами. Например, рассмотрим:

     [[ -z $name ]] 

    Оболочка будет расширять $name но, в отличие от любой другой команды, она не будет выполнять ни разбиение слов, ни генерация имени файла в результате. Например, следующее будет выполнено, несмотря на пробелы, встроенные в name :

     $ name="here and there" $ [[ -n $name ]] && echo not empty not empty 

Резюме

[ является командой и подчиняется тем же правилам, что и все другие команды, выполняемые оболочкой.

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

В V7 Unix – где дебютировал Bourne shell – [ был назван test , и он существовал только как /bin/test . Итак, код, который вы напишете сегодня:

 if [ "$foo" = "bar" ] ; then ... 

вы бы написали вместо этого как

 if test "$foo" = "bar" ; then ... 

Эта вторая нотация все еще существует, и я нахожу, что более ясно, что происходит: вы вызываете команду под названием test , которая оценивает ее аргументы и возвращает код состояния выхода, который используется, чтобы решить, что делать дальше. Эта команда может быть встроена в оболочку или может быть внешней программой .¹

[ в качестве альтернативы test пришел позже. 2 Это может быть встроенный синоним test , но он также предоставляется как /bin/[ в современных системах для оболочек, которые не имеют его как встроенный.

[ и test может быть реализован с использованием того же кода. Это имеет место для /bin/[ и /bin/test в OS X, где это жесткие ссылки на один и тот же исполняемый файл.) В результате реализация полностью игнорирует трейлинг ] : она не требует ее, если вы вызываете это как /bin/[ , и он не жалуется, если вы предоставите его /bin/test

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

Из-за этой истории часть различия между «встроенным» и «ключевым словом». Он также отражает тот факт, что правила синтаксиса для синтаксического анализа [[ выражения разные, как указано в ответе Джона1024).


Примечания:

  1. Когда вы смотрите на это, это дает понять, почему вы должны размещать пробелы вокруг [ в сценариях оболочки, в отличие от того, как скобки и скобки работают на большинстве других языков программирования. Если интерпретатор команд оболочки разрешен, if["$x"... , он также должен был бы разрешить iftest"$x"...

  2. Это произошло примерно в 1980 году. /bin/[ не существует в моей копии Ancient Unix V7 с 1979 года, и man test не man test документ как псевдоним. В соответствующей записи man-страницы у меня есть предварительная версия руководства System III с 1980 года, она указана в списке.

  3. ls -i /bin/[ /bin/test

  4. Но не рассчитывайте на это поведение. Встроенная версия Bash [ требует закрытия ] , и ее встроенная test реализация будет жаловаться, если вы ее предоставите.

  5. Различие между встроенными и внешними командами может также иметь значение по другой причине: две реализации могут вести себя по-разному. Это относится к echo во многих системах. Поскольку существует только одна реализация, такое различие не требуется для ключевого слова.

[ первоначально была только внешней командой, другим именем для /bin/test . Но несколько команд, таких как [ и echo , так часто используются в сценариях оболочки, которые разработчики оболочки решили скопировать код непосредственно в оболочку, а не запускать другой процесс каждый раз, когда они используются. Это превратило эти команды в «встроенные», хотя вы все равно можете вызывать внешнюю программу по ее полному пути.

[[ пришел намного позже. Хотя встроенный встроен внутри оболочки, он анализируется так же, как и внешние команды. Как объясняется в ответе John1024, это означает, что некотируемые переменные будут получать разбиение на них, а токены типа > и < обрабатываются как перенаправление ввода-вывода. Это затрудняет составление сложных сложных выражений сравнения. [[ был создан как синтаксис оболочки, так что он мог быть проанализирован идеосинхронно. Внутри [[ переменные не получают разбиения слов, < и > могут использоваться как операторы сравнения, = могут вести себя по-разному в зависимости от того, цитируется ли следующий параметр или нет и т. Д. Это все удобства, которые делают [[ проще использовать, чем традиционный [ command / builtin.

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

Это похоже на эволюцию, которая привела к синтаксису $((...)) для арифметических выражений, который в основном заменил традиционную команду expr .

Новый [[ в bashоптимизация [ .

Классик [ имеет один большой недостаток, когда он часто используется для выполнения тривиальной операции: каждый раз он порождает новый процесс:
(Он создает новое адресное пространство только для сравнения 0 и 1 ! Каждый раз!)

Я думаю, что основной момент добавления [[ делал оценку выражения внутри [ не порождал дополнительный процесс. Но как [ работа не может быть изменена – это создаст массу путаницы и проблем. Таким образом, оптимизация была реализована с новым именем более эффективным способом, а именно командой с встроенной оболочкой.
Он стал ключевым словом в синтаксисе оболочки как побочный эффект.

В то время [ сначала использовался, это был правильный способ сделать это с помощью внешнего процесса.

  • linux как cd к родительской папке, если она перемещается через символическую ссылку
  • Эффективная генерация stdin в сценарии оболочки
  • Проверка, является ли команда встроенной в ksh
  • Почему моя программа «set» не выполняется?
  • Трубопроводы, рабочие места и процессы в Zsh
  • Как я могу получить справочное сообщение для zsh builtin's?
  • При использовании linux acl mkdir и mkdir -p делают разные вещи
  • Количество элементов в массиве bash, где имя массива является динамическим (т.е. хранится в переменной)
  • AIX - использовать встроенные функции ksh для освобождения памяти, когда fork невозможно
  • Как конкретно запускать встроенную команду оболочки
  • Какая цель служит толстой кишки?
  • Interesting Posts

    / восстановление домашнего раздела

    Как исправить ошибку в grub.cfg из LiveCD?

    Iceweasel: изменить стандартную / домашнюю страницу с помощью командной строки

    Почему эти соединения не классифицируются как «установленные» под conntrack?

    Восстановление файла на ext3

    «Паника в ядре – не синхронизация» после создания Centos-6 / elrepo 3.10.19 ядро ​​из источника

    Удалить ключи redis, которые неактивны в течение 30 дней

    Как сделать svn сохранить учетные данные, когда –non-interactive

    Терминал Gnome — скрыть файлы тильды, созданные Emacs

    SSH через маршрутизатор на внутренний файловый сервер

    Vimrc, управление картой; к действию

    Убивание предыдущих экземпляров скрипта перед запуском того же сценария Unix

    Удалите дубликат mp3 с другим именем, размером и хешем

    Взаимодействие команд initrd и системных служб, выполняющих то же самое

    Может ли `tar -list -v` указать размер файла в формате для чтения?

    Linux и Unix - лучшая ОС в мире.