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

13

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

Джастин
источник
1
Причина, по которой вы цитируете, довольно важна. Зачем тебе больше?
тердон

Ответы:

16

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

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

read -p "Enter your name: " name
: ${name:=John Doe}  # if the user entered an empty string
echo "$name"
Гленн Джекман
источник
2
Не могли бы вы объяснить посимвольно, как работает вторая строка?
Руслан
Прочтите о расширении :команд и параметров в руководстве по bash.
Гленн Джекман
4
Чтобы обрисовать, на что ссылается @glennjackman, вторая строка вызывает пустую команду: и ${name:="John Doe"}будет расширена, что приведет к выполнению присваивания, поскольку оно читается как аргумент для:. Без: оболочка будет пытаться запустить «Джон Доу» в качестве команды или значение, $nameесли оно уже установлено
imkendal
13

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

while : ; do 
   # ....
done
choroba
источник
4
Но, возможно, while trueон более читабелен, потому что (а) он использует меньше знаков препинания и (б) он больше похож на языки, производные от Си.
wchargin
9

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

: > /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 ].)

G-Man говорит: «Восстанови Монику»
источник
5

В Unix V6 и Thompson Shell, на :самом деле, они использовались как часть gotoзаявления. Согласно инструкции , она первоначально появилась в 3-й версии Unix:

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

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

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

Сергей Колодяжный
источник
3

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

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

Без :bash генерируется синтаксическая ошибка.

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

WinEunuuchs2Unix
источник
Хороший ответ, хотя поначалу может и не быть очевидным, что это наиболее полезно для реальной команды в условиях теста, например if pgrep firefox >/dev/null ; then : ; else echo "Firefox not running"; fi, ошибка будет отображаться только в том случае, если Firefox не запущен. Другими словами, когда нужно что-то делать только тогда, когда в команде есть ошибка. В некотором смысле это эквивалентно pgrep firefox || echo "Firefox not running", хотя и более читабельно и позволяет больше команд
Сергей Колодяжный
0

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

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

#!/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).
....
Майкл Дж
источник