Почему '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 на этот скрипт.

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

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 строке не нужны, но я считаю, что лучше всего их туда поместить, чтобы будущие читатели не должны были это помнить. )

  • Как я могу создать скрипт bash, который запускает irb, а затем некоторый код ruby?
  • В чем смысл & amp в отношении тестовой команды?
  • Успешная команда командной строки Linux
  • Какова цель выполнения квадратных скобок
  • Если условие с командой ssh ​​внутри
  • Разница между ] и ]?
  • Вывести результат печати непосредственно в bash без использования if
  • Конкретная строка зависает [, [[
  • Как написать функцию в bash?
  • bash: Я сломал ]
  • Что делает ]?
  • Interesting Posts

    Использование Pipeline для прямых файлов для программы, которая открывает их

    Как я могу туннелировать трафик для NAT-узла на другой сервер?

    Нет подключения к Интернету для новой установки

    Как перезапустить скрипт python через одну секунду с помощью UPSTART?

    Сделать вкладки tmux более похожими на традиционные вкладки

    редактирование очень длинной строки, много столбцов в vim

    Неужели systemd делает dig / nslookup бесполезным?

    grep путается именами файлов с тире

    Команда для работы со всеми файлами в папке и вывода результата в один файл

    Возможно ли создать общий ресурс NFS из установочного каталога CIFS?

    Генерация MAC-адресов

    Почему ssh-copy-id запрашивает пароль локального пользователя три раза?

    Удалять строки из файлов с разделителями табуляции на основе общего столбца с другим файлом

    Умножьте определенные числа в текстовом файле определенной константой

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

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