Для чего используются : в начале строк в сценарии Bash?

Я видел некоторое использование : в начале строк, как в следующем фрагменте кода:

cgcreate -g "$cgroups:/$uuid"
: "${BOCKER_CPU_SHARE:=512}" && cgset -r cpu.shares="$BOCKER_CPU_SHARE" "$uuid"
: "${BOCKER_MEM_LIMIT:=512}" && cgset -r memory.limit_in_bytes="$((BOCKER_MEM_LIMIT * 1000000))" "$uuid"

Эксперименты показывают, что функция : очень похожа на комментарий (#), поскольку в стандартный вывод ничего не выводится; однако : $(echo foo > bar) создает новый файл bar, поэтому выполнение кода происходит.

1
Shuzheng 8 Мар 2021 в 14:19
«Выполнение кода действительно происходит», но не по той причине, по которой вы думаете. : — пустая команда, но оболочка оценивает свои аргументы, прежде чем ничего с ними не делать. Однако $( .. ) является process expansion -- содержимое ... выполняется для предоставления аргумента, прежде чем он будет отброшен. Это известный маршрут атаки путем внедрения кода.
 – 
Paul_Pedant
8 Мар 2021 в 19:57

1 ответ

$ help :
:: :
    Null command.
    
    No effect; the command does nothing.
    
    Exit Status:
    Always succeeds.

Это та же команда, что и true (за исключением того, что описание, данное help, отличается).

Примечательно, что это обычная команда, а не синтаксический элемент, поэтому он отличается от комментария тем, что остальная часть командной строки должна иметь допустимый синтаксис оболочки, и любые расширения по-прежнему имеют место.

Например. в вашем примере "${BOCKER_CPU_SHARE:=512}" - это расширение set-default-value, оно устанавливает переменную в 512, если она не установлена ​​или пуста:

$ foo=
$ : "${foo:=512}"
$ echo "$foo"
512

Но

$ foo=42
$ echo ${foo:=512}       # no change since already has value
42

В некотором смысле это расширение является сокращением от if [ -z "$foo" ]; then foo=512; fi, но работает только как расширение, поэтому для его сопровождения требуется некоторая команда. И : часто используется для этого, потому что сам по себе ничего не делает.

Однако я не уверен, в чем смысл &&, поскольку : всегда правдив, так что это можно было бы записать просто

: "${BOCKER_CPU_SHARE:=512}"
cgset -r cpu.shares="$BOCKER_CPU_SHARE" "$uuid"

И т.п.

3
ilkkachu 8 Мар 2021 в 14:27