Правила простые, но тонкие.Примеры, которые вы привели, не все эквивалентны, они имеют немного различное значение.Для достаточно хорошей справки вы можете прочитать Язык команд оболочки , который охватывает оболочки POSIX.Большинство оболочек, включая, конечно, bash, zsh и ksh, являются оболочками POSIX и будут реализовывать, по крайней мере, то, что перечислено там.Некоторые оболочки могут соответствовать более ранним версиям спецификации или быть похожими, но не совместимыми.
Основное правило, которое вам необходимо запомнить, если вы изучаете сценарии оболочки Unix, таково: выражения разделяются пробелами.Технически они разделяются теми символами, которые перечислены в переменной $ IFS, но при нормальных обстоятельствах это становится пробелом.
Если вы говорите ["$a"="$b"]
в bash, оболочка пытается прочитать всю строку как команду,оценивая $ a и $ b на месте.Предполагая, что значение $a
было литералом a
, а значение $b
было литералом b
, оболочка будет пытаться выполнить команду с именем [a=b]
, которая является допустимым именем файла.Кавычки интерпретировались оболочкой как особые, а [
- нет, потому что они особенные, только если написаны как отдельный токен.Он не был разделен пробелами.
Почти все, что вы видите и делаете в оболочке, является командой.Символ [
это не синтаксис, это команда.Команды принимают аргументы, разделенные пробелами.Что означают эти аргументы, зависит от команды, а не от оболочки.В C if ( a == b )
обрабатывается все синтаксическим анализатором, кроме значений a и b.В bash if [ "$a" == "$b" ]
сначала анализируется оболочкой, которая оценивает переменные $ a и $ b, а затем выполняется команда [
.Иногда это встроенная команда оболочки, иногда это буквально отдельный исполняемый файл (ищите /bin/[
в вашей системе).Это означает, что a == b ]
вообще не интерпретируется bash, а является своего рода языком, специфичным для предметной области, который интерпретируется как [
, который также известен как test
.На самом деле вы можете написать if test "$a" == "$b"
вместо этого.В этой форме test
не требует закрытия ]
, но все остальное тоже самое.Чтобы увидеть, что test
будет делать с этими аргументами, прочитайте help test
или man test
.
Еще одно правило, которое следует помнить при изучении сценариев оболочки Unix, таково: переменные раскрываются первыми, команды оцениваются вторыми.Это означает, что если у вас есть пробел в переменной, такой как foo="a b"
, то оболочка увидит пробел после расширения переменной: ls $foo
сам пожалуется, что не может найти файл a
и не может найтифайл b
.Чтобы получить поведение, которое вы, вероятно, ожидаете от других языков, вы почти всегда захотите заключить в кавычки свои переменные: ls "$foo"
, который указывает оболочке, что расширенная переменная должна обрабатываться как одна строка и не подвергаться повторному токенизации.
Сценарии оболочки наполнены странностями, но они не являются иррациональными (по крайней мере, в большинстве случаев).Некоторые исторические бородавки существуют, но на самом деле не так уж много правил, которые нужно помнить, как только вы получите руку с основами.Только не ожидайте, что он будет работать как обычный C-подобный язык, и вы не будете слишком удивлены.