У чому полягає корисність команди: scripting shell, якщо вона явно нічого не робить?


27

У відповіді на це запитання про коментарі в сценарії оболонок вказується, що :це команда "null", яка явно нічого не робить (але не використовується для коментарів).

Яка була б корисність команди, яка абсолютно нічого не робить?



2
Дивіться також це питання, яке має ще кращу відповідь тут , а саме те, що :потрібно бути вбудованим, а trueпоки ні, що впливає на область змінних
Old Pro

2
Це явно нічого витончено не робить .
mikeserv

Відповіді:


19

Я зазвичай використовую trueв петлях; Я думаю, що це більш зрозуміло:

while true; do
    ...
done

Я знайшов одне місце, яке :є дуже зручним, якщо ви хочете щось відповідати, але насправді нічого не хочуть робити. Наприклад:

case $answer in
    ([Yy]*) : ok ;;
    (*)     echo "stop."; exit 1 ;;
esac

3
Я згоден. trueза умову, :для НОП.
jw013

1
баш приймає case a in a ) ;; esac. Чи є якісь снаряди, які не приймають цього?
Каз

@Kaz: Відповідно до граматики оболонки POSIX , case ${var} in value);; *) do_something;; esacце прийнятно. :Команда не потрібна для порожніх справ.
Річард Хансен

12

Спочатку він використовувався для визначення, що це програма оболонки Bourne, на відміну від компільованої програми C. Це було до шибангу та декількох мов скриптів (csh, perl). Ви все ще можете запустити сценарій, починаючи з просто ::

$ echo : > /tmp/xyzzy
$ chmod +x /tmp/xyzzy
$ ./xyzzy

Зазвичай сценарій буде запущено проти $SHELL(або /bin/sh).

Відтоді головне використання - це оцінка аргументів. Я все ще використовую:

: ${EDITOR:=vim}

щоб встановити значення сценарію за замовчуванням.


11

: корисно для написання циклів, які повинні бути припинені зсередини.

while :
do
    ...stuff...
done

Це буде працювати вічно, якщо breakабо exitне викликається, або оболонка не отримує сигнал, що закінчується.


3
Я відчуваю, що while true; do ...; doneповідомляє читача про наміри краще, ніжwhile :; do ...; done
Річард Хансен

9

Коли ви хочете, щоб у сценаріїх оболонок висловлювався "якщо", ви або використовуєте умову "не", яка може виглядати goofy для деяких тестів, або ви використовуєте ":" в істинному пункті, з реальним кодом в false- стаття

if [ some-exotic-condition ]
then
    :
else
    # Real code here
fi

"Екзотичний стан" може бути чимось, що ви не хочете заперечувати, або це набагато зрозуміліше, якщо ви не використовуєте "негативну логіку".


1
Він також відображається в сценаріях, створених autoconfчерез те, що набагато простіше додати за замовчуванням :порожні гілки, ніж зрозуміти, як змінити умову.
Дітріх Епп

2
Я не можу побачити, як стирчить у !передній [ some-exotic-condition ]корінці, але зайвим : elseпісля цього не є гуфі.
Каз

@Kaz має хороший момент. Пам’ятаймо, що придумати екзотичні умови в кращому випадку складно. Якщо вам доведеться заперечувати все це, це одне, але це може просто зробити стан менш зрозумілим. Чи "!" заперечують усю умову чи лише перший термін? Найкраще іноді мати справжній пункт ':'.
Брюс Едігер

!Маркер зводить на немає всю команду елемент труби. while ! grep ... ; do ... done або if ! [ ... ] ; then ... fi. Це в основному зовнішній test/[]синтаксис. Дивіться: pubs.opengroup.org/onlinepubs/9699919799/utilities/…
Каз

5

Я коли-небудь використовував це на додаток до символу # для тимчасового коментування рядка, в ситуації, коли коментування рядка створює синтаксичну помилку через дефект граматики оболонки, що не дозволяє порожній послідовності команд :

if condition ; then
    :# temporarily commented out command
fi

Без: у нас відсутня послідовність команд, яка є синтаксичною помилкою.


4

Є два випадки, коли мені здається :корисним:

Призначення змінної за замовчуванням

#!/bin/sh

# set VAR to "default value" if not already set in the environment
: "${VAR=default value}"

# print the value of the VAR variable.  Note that POSIX says the behavior
# of echo is implementation defined if the first argument is '-n' or if any
# argument contains a '\', so use printf instead of echo.
printf '%s\n' "VAR=${VAR}"

Це зручний спосіб дозволити користувачам вашого сценарію оболонки змінювати налаштування без редагування сценарію. (Однак аргументи командного рядка є кращими, оскільки ви не ризикуєте несподіваною поведінкою, якщо у користувача випадково є змінна, яку ви використовуєте, в їх експортованому середовищі.) Ось як користувач замінить налаштування:

VAR="other value" ./script

${VAR=value}Синтаксис говорить набір VARдля valueякщо VARще не встановлено, а потім розширити до значення змінної. Оскільки нас ще не хвилює значення змінної, вона передається як аргумент команді no-op :для її викидання.

Незважаючи на те, що :це команда без операції, розширення виконується оболонкою (а не :командою!) Перед запуском :команди, так що присвоєння змінної все ще відбувається (якщо це можливо).

Також було б прийнятним trueзамість цього використовувати або якусь іншу команду :, але код стає важче читати, оскільки намір менш зрозумілий.

Наступний сценарій також працює:

#!/bin/sh

# print the value of the VAR variable.  Note that POSIX says the behavior
# of echo is implementation defined if the first argument is '-n' or if any
# argument contains a '\', so use printf instead of echo.
printf '%s\n' "VAR=${VAR=default value}"

Але сказане вище набагато складніше. Якщо ${VAR}над цим printfрядком додано рядок, що використовує, розширення призначення за замовчуванням потрібно перемістити. Якщо розробник забуде перемістити це завдання, вводиться помилка.

Щось поставити в порожній умовний блок

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

if some_condition; then
    # todo:  implement this block of code; for now do nothing.
    # the colon below is a no-op to prevent syntax errors
    :
fi

Деякі люди стверджують, що наявність порожнього істинного ifблоку може полегшити читання коду, ніж заперечення тесту. Наприклад:

if [ -f foo ] && bar || baz; then
    :
else
    do_something_here
fi

Можливо, простіше читати, ніж:

if ! [ -f foo ] || ! bar && ! baz; then
    do_something_here
fi

Однак я вважаю, що існує кілька альтернативних підходів, які є кращими від порожнього справжнього блоку:

  1. Поставте умову у функцію:

    exotic_condition() { [ -f foo ] && bar || baz; }
    
    if ! exotic_condition; then
        do_something_here
    fi
    
  2. Помістіть умову всередині фігурних дужок (або круглих дужок, але в дужках породжений процес підзагортання, і будь-які зміни, внесені до середовища в підпакеті, не будуть видні за межами нижньої оболонки) перед тим, як заперечити:

    if ! { [ -f foo ] && bar || baz; } then
        do_something_here
    fi
    
  3. Використовуйте ||замість if:

    [ -f foo ] && bar || baz || {
        do_something_here
    }
    

    Я віддаю перевагу такому підходу, коли реакція є простим однолінійним, таким як умови затвердження:

    log() { printf '%s\n' "$*"; }
    error() { log "ERROR: $*" >&2; }
    fatal() { error "$@"; exit 1; }
    
    [ -f foo ] && bar || baz || fatal "condition not met"
    

1

У старій оболонці перед бурінням у стародавніх версіях UNIX :команда спочатку була призначена для визначення міток для goto(це була окрема команда, яка звиває вхід до місця, де знаходиться мітка, тому мітки не можуть бути окремим синтаксисом, що оболонка знає про. ifбула також окремою командою.) Незабаром вона стала використовуватись для коментарів, перш ніж з'явився синтаксис коментарів ( #використовувався для зворотної області), і в наші дні існує сумісність як ні до чого.


0

Окрім використання його як твердження, яке нічого не робить, ви можете використовувати його для коментування окремих тверджень, перетворюючи їх у аргументи для:.


Це не буде точно коментарем, оскільки : echo write this line > myfileвсе одно створить порожній файл.
Арседж

5
Як пояснено в засланні в питанні, :є НЕ адекватний механізм коментування.
jw013
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.