Почему 'if ' ветвь всегда выбрана, даже если $ 1 не 1?

У меня есть сценарий оболочки с именем «teleport.sh» следующим образом:

if [ $1="1" ]; then shift mv "$@" ~/lab/Sun elif [ $1="2" ]; then shift mv "$@" ~/lab/Moon elif [ $1="3" ]; then shift mv "$@" ~/lab/Earth fi 

Когда я выполняю:

 sh teleport.sh 2 testfile 

Этот testfile перемещается в каталог ~/lab/Sun , что меня смущает, так как я не передал 1 или 1 на этот скрипт.

Что здесь не так?

  • Начиная с bash: -lt и -gt аргументы
  • Когда и когда не использовать операторы с if?
  • Проверьте, равна ли переменная открытой круглой скобке
  • Если условие работает впервые, но не во второй раз
  • Тестирование строки, содержащей только пробелы (вкладки или «»)?
  • Почему эта условная проверка bash работает с ], но не ?
  • В чем разница -a и -e в условных выражениях bash?
  • Логика Bash назад в одной системе, но не другая
  • 4 Solutions collect form web for “Почему 'if ' ветвь всегда выбрана, даже если $ 1 не 1?”

    Использование пробелов устраняет вашу проблему.

     if [ "$1" = 1 ]; then shift mv "$@" ~/lab/Sun elif [ "$1" = 2 ]; then shift mv "$@" ~/lab/Moon elif [ "$1" = 3 ]; then shift mv "$@" ~/lab/Earth fi 

    Хотя это более аккуратно:

     #!/bin/bash action=$1 shift files=("$@") case $action in 1) mv -- "${files[@]}" ~/lab/Sun ;; 2) mv -- "${files[@]}" ~/lab/Moon ;; 3) mv -- "${files[@]}" ~/lab/Earth ;; esac 

    Прежде всего, вы должны предоставить пробелы между аргументами [ , test или [[ :

     if [ "$1" = 1 ]; 

    Когда в Bash рекомендуется использовать [[ ]] поскольку он не делает ненужных для условного выражения, таких как разбиение слов и расширение пути. Цитирование двоичных кавычек также не требуется. Также можно использовать более читаемый оператор == .

     if [[ $1 == 1 ]]; 

    Добавлено примечание: если второй операнд также содержит переменные, необходимо использовать цитирование, поскольку оно может быть подвергнуто сопоставлению с образцом, если оно содержит распознаваемые символы, такие как * ? , [] и т. д. Если расширенное globbing или сопоставление с образцом включено с shopt -s extglob , другие формы, такие как @() !() и т. д., также будут распознаваться как шаблоны. См. Соответствие шаблонов .

    С такими операторами, как < и > это может быть необходимо, поскольку я когда-то сталкивался с ошибкой, где не цитирование второго аргумента приводило к различным результатам.

    Что касается первого операнда, ничего не применяется.

    Рассмотрим также более простое изменение:

     case "$1" in 1) mv -- "${@:2}" ~/lab/Sun ;; 2) mv -- "${@:2}" ~/lab/Moon ;; 3) mv -- "${@:2}" ~/lab/Earth ;; esac 

    Или сгущенный:

     case "$1" in 1) mv -- "${@:2}" ~/lab/Sun ;; 2) mv -- "${@:2}" ~/lab/Moon ;; 3) mv -- "${@:2}" ~/lab/Earth ;; esac 

    "${@:2}" – это форма расширения подстроки или расширения члена массива, где 2 – смещение. Это означает, что начало расширения начинается со второго значения. При этом нам может не понадобиться использовать shift .

    Добавленный -- запрещает mv распознавать имена файлов, начиная с тире ( - ) как недопустимые параметры.

    Чтобы ответить на вопрос о том, почему это происходит, это поведение [ aka test зарегистрировано в POSIX :

    В следующем списке $ 1, $ 2, $ 3 и $ 4 представляют аргументы, представленные для теста:

    […]

    1 аргумент:

    Exit true (0), если $ 1 не является нулевым; в противном случае выйдите из ложного.

    Вы передаете ему 1 аргумент, 2=1 , который не является нулевым и, следовательно, успешно завершает работу с выходами.

    Как указывают другие сообщения (и shellcheck ), если вы хотите сравнить для равенства, вам вместо этого нужно будет передать 3 аргумента 2 , = и 1 .

    Я просто хочу рекомендовать портативную, но еще более опрятную альтернативу. Bash не является универсальным (и если вам не нужен универсальный, почему вы пишете сценарий оболочки?)

     #! /bin/sh action="$1" shift case "$action" in 1) dest=Sun ;; 2) dest=Moon ;; 3) dest=Earth ;; *) echo "Unrecognized action code '$action' (must be 1, 2, or 3)" >&2; exit 1 ;; esac mv -- "$@" ~/lab/"$dest" 

    (Примечание для педантов: да, я знаю, что цитаты вокруг $action в case "$action" in строке не нужны, но я считаю, что лучше всего их туда поместить, чтобы будущие читатели не должны были это помнить. )

    Interesting Posts

    Как изменить конфигурацию eth0 без перезагрузки другого интерфейса (CentOS, Redhat)

    Как установить / установить mutt с Gmail на CentOS и Ubuntu?

    Что такое использование; в одной строке?

    Система зависает. В журналах ничего не найти

    Как навсегда отключить сетевой интерфейс?

    Как планировать выполнение задачи cron

    Безопасное удаление каталога только в том случае, если оно не является точкой монтирования

    Что я делаю неправильно, пытаясь написать сценарий bash, который возвращает номер следующего доступного порта?

    Как заставить iwconfig полностью работать с встроенным Linux

    wget рекурсивный только для файлов, которые передают регулярное выражение

    Ubuntu live RTMP video streem

    Заблокировать пакет для удаления в APT

    Вывод скрипта в зависимости от параметра

    DNSCrypt, Unbound и DNSSEC

    Почему я не могу использовать расширение вкладки / автозаполнение переменных оболочки с помощью cd?

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