Каков предел использования noop [:] в bash?

Я искал noop в bash (:), но не смог найти никакой хорошей информации. Какова цель или использование этого оператора?

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

[[email protected]]$ a=11
[[email protected]]$ b=20
[[email protected]]$ c=30
[[email protected]]$ echo $a; : echo $b ; echo $c
10
30

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

Ответ 1

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

while true; do
  echo 'Going on forever'
done

Традиционно использовать :, когда синтаксис оболочки требует команды, но вам нечего делать.

while keep_waiting; do
  : # busy-wait
done

Встраиваемые даты : вернулись к оболочке Thompson, это было присутствует в Unix v6. : был индикатором ярлыка для инструкции оболочки Thompson goto. Метка может быть любым текстом, поэтому : удваивается как индикатор комментария (если нет goto comment, то : comment является фактически комментарием). Bourne shell не имел goto, но сохранял :.

Общей идиомой, использующей :, является : ${var=VALUE}, которая устанавливает var в VALUE, если она была отменена и ничего не делает, если var был уже установлен. Эта конструкция существует только в виде подстановки переменных, и эта подстановка переменной должна быть частью команды как-то: команда no-op отлично работает.

См. также Какую цель выполняет служба толстой кишки?.

Ответ 2

Я использую его для операторов if, когда комментирую весь код. Например, у вас есть тест:

if [ "$foo" != "1" ]
then
    echo Success
fi

но вы хотите временно прокомментировать все, что содержится внутри:

if [ "$foo" != "1" ]
then
    #echo Success
fi

Что вызывает bash, чтобы дать синтаксическую ошибку:

line 4: syntax error near unexpected token `fi'
line 4: `fi'

Bash не может иметь пустые блоки (WTF). Поэтому вы добавляете no-op:

if [ "$foo" != "1" ]
then
    #echo Success
    :
fi

или вы можете использовать no-op для комментариев строк:

if [ "$foo" != "1" ]
then
    : echo Success
fi

Ответ 3

Вы использовали бы :, чтобы предоставить команду, которая преуспевает, но ничего не делает. В этом примере команда "verbosity" по умолчанию отключена, установив ее на :. Опция 'v' включает ее.

#!/bin/sh
# example
verbosity=:                         
while getopts v OPT ; do          
   case $OPT in                  
       v)        
           verbosity=/bin/realpath 
       ;;
       *)
           exit "Cancelled"
       ;;             
   esac                          
done                              

# `$verbosity` always succeeds by default, but does nothing.                              
for i in * ; do                   
  echo $i $($verbosity $i)         
done                              

$ example
   file

$ example -v
   file /home/me/file  

Ответ 4

Если вы используете set- e, тогда || : - отличный способ не выходить из script, если происходит сбой (он явно пропускает его).

Ответ 5

Игнорировать аргументы alias

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

> alias alert_with_args='echo hello there'

> alias alert='echo hello there;:'

> alert_with_args blabla
hello there blabla

> alert blabla
hello there

Ответ 6

Одно использование - это многострочные комментарии или комментировать часть кода для целей тестирования, используя его в сочетании с файлом здесь.

: << 'EOF'

This part of the script is a commented out

EOF

Не забудьте использовать кавычки вокруг EOF, чтобы любой код внутри не оценивался, например $(foo). Также может быть полезно использовать интуитивное имя терминатора, например NOTES, SCRATCHPAD или TODO.

Ответ 7

Два моих.

Вставить комментарии POD

Довольно фанковое приложение : предназначено для вложения комментариев POD в сценарии bash, так что страницы руководства могут быть быстро сгенерированы, Конечно, можно было бы переписать весь script в Perl; -)

Включение функции времени выполнения

Это своего рода шаблон кода для функций привязки во время выполнения. F.i., имеют функцию отладки, чтобы что-то делать, только если установлен определенный флаг:

#!/bin/bash
# noop-demo.sh 
shopt -s expand_aliases

dbg=${DBG:-''}

function _log_dbg {
    echo >&2 "[DBG] [email protected]"
}

log_dbg_hook=':'

[ "$dbg" ] && log_dbg_hook='_log_dbg'

alias log_dbg=$log_dbg_hook


echo "Testing noop alias..."
log_dbg 'foo' 'bar'

Вы получаете:

$ ./noop-demo.sh 
Testing noop alias...
$ DBG=1 ./noop-demo.sh 
Testing noop alias...
[DBG] foo bar

Ответ 8

Иногда предложения no-op могут сделать ваш код более удобочитаемым.

Это может быть вопросом мнения, но вот пример. Предположим, что вы создали функцию, которая работает, используя два пути unix. Он вычисляет "путь изменения", необходимый для cd, с одного пути на другой. Вы помещаете ограничение на свою функцию, что пути должны начинаться с символа '/' ИЛИ ​​оба не должны.

function chgpath() {
    # toC, fromC are the first characters of the argument paths.
    if [[ "$toC" == / && "$fromC" == / ]] || [[ "$toC" != / && "$fromC" != / ]]
    then
        true      # continue with function
    else
        return 1  # Skip function.
    fi

Некоторые разработчики захотят удалить no-op, но это будет означать отрицание условного:

function chgpath() {
    # toC, fromC are the first characters of the argument paths.
    if [[ "$toC" != / || "$fromC" == / ]] && [[ "$toC" == / || "$fromC" != / ]]
    then
        return 1  # Skip function.
    fi

Теперь, по моему мнению, не так ясно из условия if-условия условия, в которых вы хотите пропустить выполнение функции. Чтобы исключить no-op и сделать это ясно, вы хотели бы переместить if-предложение из функции:

    if [[ "$toC" == / && "$fromC" == / ]] || [[ "$toC" != / && "$fromC" != / ]]
    then
        cdPath=$(chgPath pathA pathB)   # (we moved the conditional outside)

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

Итак, как часто это происходит? Не очень часто. Может быть, раз или два раза в год. Это случается достаточно часто, чтобы вы знали об этом. Я не уклоняюсь от использования, когда думаю, что это улучшает читаемость моего кода (независимо от языка).

Ответ 9

В некоторой степени связанный с этим ответом, я считаю, что этот вариант не очень удобен для взлома сценариев полиглота. Например, вот правильный комментарий как для bash, так и для vimscript:

":" #    this is a comment
":" #    in bash, ‘: is a no-op and ‘# starts a comment line
":" #    in vimscript, ‘" starts a comment line

Конечно, мы, возможно, использовали true точно так же, но : знак препинания, а не нерелевантное английское слово дает понять, что это синтаксический маркер.


Что касается того, почему кто-то может сделать такую хитрую вещь, как написание сценария полиглота (помимо того, что это круто): это оказывается полезным в ситуациях, когда мы обычно пишем несколько файлов сценариев на нескольких разных языках, причем файл X ссылается на файл Y

В такой ситуации объединение обоих сценариев в одном файле полиглота позволяет избежать любой работы в X по определению пути к Y (это просто "$0"). Что еще более важно, это делает более удобным перемещение или распространение программы.

  • Типичный пример. Существует известная, длинная проблема -S с шебангами: большинство систем (включая Linux и Cygwin) допускают, чтобы интерпретатору передавался только один аргумент. Следующий шебанг:

    #!/usr/bin/env interpreter --load-libA --load-libB
    

    сработает следующая команда:

    /usr/bin/env "interpreter --load-libA --load-libB" "/path/to/script"
    

    а не предназначено:

    /usr/bin/env interpreter --load-libA --load-libB "/path/to/script"
    

    Таким образом, вы бы в итоге написали скрипт-обертку, такой как:

    #!/usr/bin/env sh
    /usr/bin/env interpreter --load-libA --load-libB "/path/to/script"
    

    Здесь полиглоссия выходит на сцену.

  • Более конкретный пример. Однажды я написал скрипт bash, который, помимо прочего, вызывал Vim. Мне нужно было дать Vim дополнительную настройку, что можно сделать с помощью опции --cmd "arbitrary vimscript command here". Однако эта настройка была существенной, так что встраивание ее в строку было бы ужасным (если возможно). Следовательно, лучшим решением было бы написать его в виде extenso в каком-либо файле конфигурации, а затем заставить Vim прочитать этот файл с помощью -S "/path/to/file". Поэтому я получил файл bash/vimscript для полиглота.

Ответ 10

Предположим, у вас есть команда, которую вы хотите связать с успехом другой:

cmd="some command..."
$cmd
[ $? -eq 0 ] && some-other-command

но теперь вы хотите выполнить команды условно и показать команды, которые будут выполнены (пробный запуск):

cmd="some command..."
[ ! -z "$DEBUG" ] && echo $cmd
[ -z "$NOEXEC" ] && $cmd
[ $? -eq 0 ] && {
    cmd="some-other-command"
    [ ! -z "$DEBUG" ] && echo $cmd
    [ -z "$NOEXEC" ] && $cmd
}

так что если вы установите DEBUG и NOEXEC, вторая команда никогда не появится. это потому, что первая команда никогда не выполняется (потому что NOEXEC не является пустой), но при оценке этого факта возвращается значение 1, что означает, что подчиненная команда никогда не выполняется (но вы этого хотите, потому что это пробный запуск). чтобы исправить это, вы можете сбросить значение выхода, оставленное в стеке, с помощью noop:

[ -z "$NOEXEC" ] && $cmd || :