Я пытался сравнить, равны ли два числа в Bash (и печатать сообщение, если они равны), но я получаю некоторые странные сообщения об ошибках для этой простой программы:
Соответствующие ошибки отображаются ниже строк, вызвавших эти ошибки.
Ответ 3
Shell scripting на самом деле не был полным языком, и он сильно зависит от работы других внешних команд.
Переменные используют сигилу, которая составляет $
перед ними. Многие языки сценариев оболочки используют переменные сигилы, чтобы различать строку и переменную.
Например:
foo=foo_value
echo foo foo $foo foo
Будет печать:
foo foo foo_value foo
Обратите внимание, что кавычки не нужны для выражения echo для строк. Пакет Windows Batch очень похож:
set foo = foo_value
echo foo foo %foo% foo
Как вы можете видеть, сигил используется, когда переменная предположительно расширяется, но не тогда, когда вы ее определяете. Это потому, что оболочки Unix являются интеллектуальными оболочками. Они запускают командную строку, прежде чем она будет выполнена. Оболочка заменит переменные среды перед выполнением:
foo=bar
$foo="whose value is this" #Note the dollar sign!
echo The value of foo is $foo
echo The value of bar is $bar
Это напечатает:
The value of foo is foo
The value of bar is whose value is this
Если вы используете команду set -xv
, вы увидите, что $foo="whose value is this"
разворачивается до bar=whose value is this"
до его выполнения.
В оболочках Bourne, таких как Kornshell и BASH, утверждение if
не то, что вы думаете. Команда if
выполняет оператор и выберет предложение if, если эта команда возвращает нулевое значение. Например:
cat "foo" > my_file #Create a one line file with the string foo in it.
if grep -q "foo" my_file #grep command will return a zero exit code if it finds foo
then
echo "The string 'foo' is in file my_file"
fi
Обратите внимание, что предложение if не является логическим выражением. Это действительная команда, которая выполняется.
Где-то в начале разработки Unix была создана test
команда. Вы можете сделать мужской тест и посмотреть, как его использовать.
Команда test
позволяет вам сделать это:
foo=3
bar=3
if test foo -eq bar
then
echo "foo and bar are equal"
else
echo "foo and bar are not equal"
fi
Если вы это сделаете:
$ ls -li /bin/test /bin/[
Вы увидите, что команда под названием [
самом деле существует и является жесткой ссылкой на test
команду. Это было создано, чтобы выражение if
выглядело скорее как оператор if, который вы увидите на обычных языках программирования:
foo=3
bar=3
if [ foo -eq bar ]
then
echo "foo and bar are equal"
else
echo "foo and bar are not equal"
fi
Точно такой же скрипт, как и выше, но с [
вместо test
.
Это объясняет, почему вам нужно тире во многих тестах (это параметр для команды test
, а параметры начинаются с тире!). Это также объясняет, почему вам нужны пробелы вокруг [
и ]
. Это настоящие команды Unix, а команды Unix должны иметь пробелы вокруг них, поэтому оболочка может их обрабатывать.
Еще одна проблема заключается в том, почему оболочка имеет два разных набора тестов для строк и чисел. Это потому, что строки могут содержать только цифры, но не являются числовыми. Например, если вы делаете инвентарь, у вас может быть номер детали 001
и 01
. Численно они равны, но, как строки, это две разные строки. Сценарий оболочки не знает. Вместо этого вы должны сообщить сценарию оболочки, если это числовое сравнение или сравнение строк.
Perl имеет похожие проблемы, поскольку вы не объявляете переменные числовыми или нечисловыми:
Shell Script Perl
Boolean Operator Numeric String Numeric String
=================== ======= ====== ======= ======
Equals -eq = == eq
Not Equals -ne != != ne
Greater Than -gt > > gt
Less Than -lt < < lt
Greater or Equals -ge >= >= ge
Less Than or Equals -le <= <= le
Вы можете попробовать несколько других вещей:
$ echo "*" #Echos the asterisk
$ echo * #No quotes: Prints all files in current directory
Обратите внимание, что оболочка расширяет *
перед выполнением команды echo. Это основное различие между сценарием оболочки и типичным языком программирования. Сначала оболочка расширяет (заполняет переменные среды, подстановку глобусов, подкоды запуска), прежде чем она действительно выполнит команду.
set -xv
покажет вам, какая команда выполняется, и как оболочка расширяет команду перед выполнением. Выполнение set +xv
отключит это. Поиграйте с этим, и вы скоро поймете оболочку немного лучше.