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

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

 [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]

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

  • Команда, которая дает имя пользователя @ hostname: pwd
  • встроенный возврат
  • Пример использования / практический пример для встроенного exec Bash
  • В чем разница между встроенной командой и тем, что нет?
  • AIX - использовать встроенные функции ksh для освобождения памяти, когда fork невозможно
  • Выход трубы Bash на большее количество
  • Трубопроводы, рабочие места и процессы в Zsh
  • В чем разница между тем, где и где
  • 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 и Unix - лучшая ОС в мире.