Какой смысл в нулевом операторе bash ":", двоеточие?

В чем смысл "нулевого" оператора в скрипте BASH? Я понимаю, что он используется в качестве заполнителя после if Команда, когда вам нечего сказать, но вам нужна команда, чтобы программа работала правильно. Но каково общее использование этого? Когда бы вы использовали это? Когда имеет смысл его использовать?

7 ответов

Иногда полезно разрешить побочные эффекты расширения параметров.

Например, установка значения по умолчанию

read -p "Enter your name: " name
: ${name:=John Doe}  # if the user entered an empty string
echo "$name"

Вы также можете использовать его для бесконечных циклов:

while : ; do 
   # ....
done

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

: > /path/to/file

Это бесконечно быстрее, чем touch /path/to/file(так как это не требует запуска touch программа) и может быть немного более портативным, чем просто

> /path/to/file

который, кажется, работает на многих системах. Точно так же это может использоваться, чтобы проверить, есть ли у вас доступ на запись к файлу:

if { : >> /path/to/file;} 2> /dev/null
then
    echo "writeable"
else
    echo "write permission denied"
fi

хотя это также, как правило, можно сделать без :, Предостережения:

  • Это не проверяет, существует ли файл уже. Если этого не произойдет, будет создан файл, если у него есть разрешение на это.
  • Если файл не существует, а ваш сценарий не имеет разрешения на его создание, это сообщит "Отказано в разрешении на запись".

(См. Связанный вопрос по причинам, почему это более надежно, чем if [ -w /path/to/file ].)

Еще в Unix V6 и Thompson Shell : был фактически использован как часть goto заявление. Согласно инструкции, она первоначально появилась в версии 3 Unix:

Во всем командном файле ищется строка, начинающаяся с: как первый непустой символ, за которым следуют один или несколько пробелов, а затем метка. Если такая строка найдена, goto перемещает смещение командного файла на строку после метки и завершает работу. Это заставляет оболочку переходить на помеченную строку.

В наши дни в bash, он используется в качестве оператора без операции, возвращая успех. Действительно, если вы посмотрите на исходный код, вы увидите, что оба true а также : использовать ту же функцию, int colon_builtin()внизу. Нет никаких : не встроенная команда и /bin/true на самом деле довольно большая команда для того, что он делает.

: может использоваться где угодно true используется, например, в command_that_can_fail || trueВпрочем, это может сбить с толку неспециалистов. Подробнее об этом читайте здесь.

Вы можете использовать его на положительном тесте if Команда, когда вы хотите сделать что-то только на отрицательной стороне. Например:

if [[ True == False ]]; then
    :
else
    echo "true <> flase"
fi

Без : Bash будет генерировать синтаксическую ошибку.

Это упрощенный пример. Обычно вы используете такую ​​технику в предварительном кодировании, когда вы еще не написали этот сегмент кода, и вам просто нужно что-то, что не вызывает ошибку.

Я просто использовал его в сценарии с командами SSH, чтобы избежать ошибок в сценарии.

В этом случае я хочу посмотреть, сможет ли пользователь подключиться к набору серверов. Если соединение в порядке, удаленный хост будет отображать эхо OK. Если соединение не удается, SSH ответит с ошибкой. Тем не менее, я хочу, чтобы мой сценарий завершился с 0, а не со значением команды SSH, если он потерпит неудачу. Так что, по сути, я фиксирую ошибку SSH, обращаясь к ней || с нулевой командой :, Выглядит так:

#!/bin/bash
for i in $(cat servers.txt); do
    echo -n "$i "; 
    ssh user@${i} 'echo OK' || :; 
done

Таким образом я получаю вывод из SSH, но не код ошибки:

....
swl06 ok
swl07 ok
swl08 Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
swl09 ok
swl10 Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
....

glenn jackman выше правильный, но вот подробное объяснение того, что делает этот оператор:

Предотвращает запуск результата как команды

По сути, нулевой оператор предотвращает запуск результата расширения параметра в качестве команды.

Вот пошаговое объяснение того, как это работает.

Запустить команду в bash
      # Runs 'curl'
curl
Определите переменные и запустите их как команды в bash
      # Define variables
EXISTING_COMMAND=curl
EMPTY_COMMAND=

# Runs the 'curl' command with no flags or arguments
${EXISTING_COMMAND}

# Runs the empty command, effectively doing nothing
${EMPTY_COMMAND}
Переназначьте переменную, если она пуста, а затем запустите ее как команду
      # Define variables
EMPTY_COMMAND=

# Assigns 'curl' to the EMPTY_COMMAND variable, then runs 'curl'
${EMPTY_COMMAND:=curl}

# Runs 'curl'
${EMPTY_COMMAND}

Вам не обязательно передавать литерал по умолчанию. Вы также можете использовать расширение параметров, как в${EMPTY_COMMAND:=${EXISTING_COMMAND}}

Выполнить пустую цепочку объединения для переменной
      TARGET_VAR=
OPTION_A=
OPTION_B=

# Skips OPTION_A and OPTION_B since they are empty too, then assigns 'curl'
: ${TARGET_VAR:=${OPTION_A:=${OPTION_B:=curl}}}

Я не рекомендую это, поскольку обаOPTION_AиOPTION_Bбудет перезаписан с помощьюcurlтакже.

НЕ запускайте переменную как команду
      # Define variables
EXISTING_COMMAND=curl

# Doens't do anything
: ${EXISTING_COMMAND}
Переназначьте переменную, если она пуста, и НЕ запускайте ее как команду.
      # Define variables
EXISTING_COMMAND=curl
EMPTY_COMMAND=

# Assigns 'curl' to the EMPTY_COMMAND variable
: ${EMPTY_COMMAND:=${EXISTING_COMMAND}}

# echo's 'curl' as text
echo ${EMPTY_COMMAND}

всегда возвращает:

Как указано в нескольких ответах выше, оператор then, если его рассматривать как команду, всегда будет возвращать , что эффективно оценивается как true при использовании в качестве условного выражения.

Обычно команды условно возвращаются, чтобы указать на успешное выполнение или на любое положительное число, например1, чтобы указать, что произошла ошибка.

Curl возвращает положительное значение без флагов и/или аргументов
      # Runs 'curl', then echo's 'False'
if curl ; then
    echo 'True'
else
    echo 'False'
fi
Curl возвращает значение с допустимыми флагами и аргументами
      # Runs 'curl --version', then echo's 'False'
if curl --version ; then
    echo 'True'
else
    echo 'False'
fi
:возвращение0значение с допустимыми флагами и аргументами
      # Runs ':', then echo's 'True'
if : ; then
    echo 'True'
else
    echo 'False'
fi
Другие вопросы по тегам