在bash中noop [:]的用例是什么?

时间:2012-09-13 10:55:05

标签: bash shell noop

我在bash(:)中搜索了noop,但是找不到任何好的信息。该运营商的确切目的或用例是什么?

我试过跟随它,它对我来说是这样的:

[mandy@root]$ a=11
[mandy@root]$ b=20
[mandy@root]$ c=30
[mandy@root]$ echo $a; : echo $b ; echo $c
10
30

请让我知道此运营商的任何实例或必须使用的任何用例。

12 个答案:

答案 0 :(得分:142)

由于历史原因,还有更多。内置:的冒号与true完全相同。当返回值很重要时,例如在无限循环中使用true是传统的:

while true; do
  echo 'Going on forever'
done

当shell语法需要命令但你无所事事时,使用:是传统的。

while keep_waiting; do
  : # busy-wait
done

:内置日期一直追溯到Thompson shellpresent中的Unix v6:是Thompson shell goto语句的标签指示符。标签可以是任何文字,因此:加倍作为评论指标(如果没有goto comment,则: comment实际上是评论)。 Bourne shell没有goto但保留:

使用:的常见习语是: ${var=VALUE},如果var未设置,则将VALUE设置为var,如果已设置{{1}}则不执行任何操作。这个构造只以变量替换的形式存在,并且这个变量替换需要以某种方式成为命令的一部分:no-op命令很好地服务。

另见What purpose does the colon builtin serve?

答案 1 :(得分:12)

当我注释掉所有代码时,我将它用于if语句。例如,你有一个测试:

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

但您想暂时注释掉其中包含的所有内容:

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

导致bash出现语法错误:

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

Bash不能有空块(WTF)。所以你添加了一个no-op:

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

或者您可以使用no-op来注释掉这些行:

{{1}}

答案 2 :(得分:7)

您可以使用:提供成功但无法执行任何操作的命令。在这个例子中,"冗长"默认情况下,通过将命令设置为:来关闭命令。 ' 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  

答案 3 :(得分:7)

如果您使用set- e,那么|| :退出脚本的好方法,如果发生故障(它明确通过)。

答案 4 :(得分: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

答案 5 :(得分:4)

一种用途是作为多行注释,或者通过将其与此文件结合使用来注释掉部分代码以进行测试。

: << 'EOF'

This part of the script is a commented out

EOF

请勿忘记在EOF周围使用引号,以便内部的任何代码都不会被评估,例如$(foo)。使用直观的终结符名称(例如NOTESSCRATCHPADTODO也可能值得。

答案 6 :(得分:3)

我的两个。

嵌入POD评论

:的{​​{1}}非常时髦的应用程序适用于embedding POD comments in bash scripts,因此可以快速生成手册页。当然,最终会用Perl重写整个脚本; - )

运行时函数绑定

这是一种在运行时绑定函数的代码模式。 F.i.,只有在设置了某个标志时才有调试功能:

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

dbg=${DBG:-''}

function _log_dbg {
    echo >&2 "[DBG] $@"
}

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

答案 7 :(得分:2)

有时,无操作条款可以使您的代码更具可读性。

这可能是一个意见问题,但这是一个例子。让我们假设你已经创建了一个通过两个unix路径工作的函数。它计算了“改变路径”。需要cd从一个路径到另一个路径。您对功能设置了一个限制,即路径必须以&#39; /&#39;开头。或两者都不能。

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-clause开始,你想要跳过这个功能的条件就不那么清楚了。要消除no-op并清楚地做到,你可能希望将if子句移出函数:

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

看起来更好,但很多时候我们无法做到这一点;我们希望在函数内部完成检查。

那么这种情况多久发生一次?不经常。也许一年一到两次。它经常发生,你应该知道它。当我认为它提高了我的代码的可读性(无论语言如何)时,我不会回避使用它。

答案 8 :(得分:1)

this answer有关,我发现这种无操作非常容易破解polyglot脚本。例如,以下是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")的任何工作。更重要的是,它使移动或分发程序更加方便。

  • 一个常见示例。 shebang的问题是一个长期存在的众所周知的问题:大多数系统(包括Linux和Cygwin)仅允许一个参数传递给口译员。以下shebang:

    #!/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"完成。但是,这种设置非常重要,因此将其内联到字符串中将是很糟糕的(如果可能的话)。因此,更好的解决方案是将其扩展写入某些配置文件,然后使Vim使用-S "/path/to/file"读取该文件。因此,我最终得到了一个多语言的bash / vimscript文件。

答案 9 :(得分:1)

我也在其中使用了脚本来定义默认变量。

repositories {
  mavenLocal {
     content {
        includeGroupByRegex "REGEX"
     }
  }
  maven {
     url "REPO_URL"
  }        
}

答案 10 :(得分:0)

假设您有一个希望链接到另一个命令的命令:

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 || :

答案 11 :(得分:0)

我有时在Docker文件上使用它来保持RUN命令对齐,如下所示:

RUN : \
    && somecommand1 \
    && somecommand2 \
    && somecommand3

对我来说,它的阅读效果优于:

RUN somecommand1 \
    && somecommand2 \
    && somecommand3

但是,这当然只是一个偏好问题