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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12404661/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 22:40:45  来源:igfitidea点击:

What is the use case of noop [:] in bash?

bashshellnoop

提问by Mandar Pande

I searched for noop in bash (:), but was not able to find any good information. What is the exact purpose or use case of this operator?

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

I tried following and it's working like this for me:

我尝试了以下操作,它对我来说是这样的:

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

Please let me know, any use case of this operator in real time or any place where it is mandatory to use it.

请让我知道这个操作符的任何实时用例或任何必须使用它的地方。

回答by Gilles 'SO- stop being evil'

It's there more for historical reasons. The colon builtin :is exactly equivalent to true. It's traditional to use truewhen the return value is important, for example in an infinite loop:

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

while true; do
  echo 'Going on forever'
done

It's traditional to use :when the shell syntax requires a command but you have nothing to do.

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

while keep_waiting; do
  : # busy-wait
done

The :builtin dates all the way back to the Thompson shell, it was presentin Unix v6. :was a label indicator for the Thompson shell's gotostatement. The label could be any text, so :doubled up as a comment indicator (if there is no goto comment, then : commentis effectively a comment). The Bourne shelldidn't have gotobut kept :.

:内置日期全部回到原来的老路汤普森壳,它是目前Unix的V6发动机:是 Thompson shellgoto语句的标签指示符。标签可以是任何文本,因此可以:兼作注释指示符(如果没有goto comment,则: comment实际上是注释)。在Bourne shell中没有goto但保留:

A common idiom that uses :is : ${var=VALUE}, which sets varto VALUEif it was unset and does nothing if varwas already set. This construct only exists in the form of a variable substitution, and this variable substitution needs to be part of a command somehow: a no-op command serves nicely.

一个常见的成语使用:: ${var=VALUE},这台varVALUE,如果它被清除的和做什么,如果var已被设置。这个结构仅以变量替换的形式存在,并且这个变量替换需要以某种方式成为命令的一部分:无操作命令很好地服务。

See also What purpose does the colon builtin serve?.

另请参阅冒号内置函数的用途是什么?.

回答by Stephen Ostermiller

I use it for if statements when I comment out all the code. For example you have a test:

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

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

but you want to temporarily comment out everything contained within:

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

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

Which causes bash to give a syntax error:

这导致 bash 给出语法错误:

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

Bash can't have empty blocks (WTF). So you add a no-op:

Bash 不能有空块 (WTF)。所以你添加一个空操作:

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

or you can use the no-op to comment out the lines:

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

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

回答by Chris Pfohl

If you use set- ethen || :is a great way to notexit the script if a failure happens (it explicitly makes it pass).

如果您使用set- ethen 则|| :是在发生故障时退出脚本的好方法(它明确地使它通过)。

回答by Mark

You would use :to supply a command that succeeds but doesn't do anything. In this example the "verbosity" command is turned off by default, by setting it to :. The 'v' option turns it on.

您将用于:提供一个成功但不执行任何操作的命令。在本例中,“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  

回答by Ulysse BN

Ignore aliasarguments

忽略alias参数

Some times you want to have an alias that doesn't take any argument. You can do it using ::

有时你想要一个不带任何参数的别名。您可以使用:

> alias alert_with_args='echo hello there'

> alias alert='echo hello there;:'

> alert_with_args blabla
hello there blabla

> alert blabla
hello there

回答by Geoffrey Ritchey

One use is as multiline comments, or to comment out part of your code for testing purposes by using it in conjunction with a here file.

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

: << 'EOF'

This part of the script is a commented out

EOF

Don't forget to use quotes around EOFso that any code inside doesn't get evaluated, like $(foo). It also might be worth using an intuitive terminator name like NOTES, SCRATCHPAD, or TODO.

不要忘记使用引号,EOF这样里面的任何代码都不会被评估,比如$(foo). 它也可能会使用一个直观的终结名字一样值得NOTESSCRATCHPADTODO

回答by sphakka

Two of mine.

我的两个。

Embed POD comments

嵌入 POD 评论

A quite funky application of :is for embedding POD comments in bash scripts, so that man pages can be quickly generated. Of course, one would eventually rewrite the whole script in Perl ;-)

一个非常时髦的应用程序:在 bash 脚本中嵌入 POD 注释,以便可以快速生成手册页。当然,人们最终会用 Perl 重写整个脚本;-)

Run-time function binding

运行时函数绑定

This is a sort of code pattern for binding functions at run-time. F.i., have a debugging function to do something only if a certain flag is set:

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

#!/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'

You get:

你得到:

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

回答by Ma?lan

Somewhat related to this answer, I find this no-op rather convenient to hack polyglotscripts. For example, here is a valid comment both for bash and for vimscript:

此答案有些相关,我发现此无操作对于破解多语言脚本非常方便。例如,这里是 bash 和 vimscript 的有效注释:

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

Sure, we may have used truejust as well, but :being a punctuation sign and not an irrelevant English word makes it clear that it is a syntax token.

当然,我们可能也用过true,但:作为标点符号而不是不相关的英语单词,这清楚地表明它是一个语法标记。



As for whywould someone do such a tricky thing as writing a polyglot script (besides it being cool): it proves helpful in situations where we would normally write several script files in several different languages, with file Xreferring to file Y.

至于为什么有人会做像编写多语言脚本这样棘手的事情(除了它很酷):这在我们通常用几种不同的语言编写多个脚本文件的情况下证明是有帮助的,文件X指的是 file Y

In such a situation, combining both scripts in a single, polyglot file avoids any work in Xfor determining the path to Y(it is simply "$0"). More importantly, it makes it more convenient to move around or distribute the program.

在这种情况下,将两个脚本组合在一个多语言文件中可以避免任何X确定路径的工作Y(它只是"$0")。更重要的是,它可以更方便地移动或分发程序。

  • A common example.There is a well-known, long-standing issue with shebangs: most systems (including Linux and Cygwin) allow only oneargument to be passed to the interpreter. The following shebang:

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

    will fire the following command:

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

    and not the intended:

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

    Thus, you would end up writing a wrapper script, such as:

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

    This is where polyglossia enters the stage.

  • A more specific example.I once wrote a bash script which, among other things, invoked Vim. I needed to give Vim additional setup, which could be done with the option --cmd "arbitrary vimscript command here". However, that setup was substantial, so that inlining it in a string would have been terrible (if ever possible). Hence, a better solution was to write it in extensoin some configuration file, then make Vim read that file with -S "/path/to/file". Hence I ended up with a polyglot bash/vimscript file.

  • 一个常见的例子。shebangs 有一个众所周知的长期存在的问题:大多数系统(包括 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"。但是,该设置非常重要,因此将其内联到字符串中会很糟糕(如果可能的话)。因此,更好的解决方案是将它写入某个配置文件中的 extenso中,然后让 Vim 使用-S "/path/to/file". 因此我最终得到了一个多语言的 bash/vimscript 文件。

回答by Bitdiot

Sometimes no-op clauses can make your code more readable.

有时 no-op 子句可以使您的代码更具可读性。

That can be a matter of opinion, but here's an example. Let's suppose you've created a function that works by taking two unix paths. It calculates the 'change path' needed to cd from one path to another. You place a restriction on your function that the paths must both start with a '/' OR both must not.

这可能是一个意见问题,但这里有一个例子。假设您已经创建了一个通过采用两个 unix 路径来工作的函数。它计算从一个路径切换到另一个路径所需的“更改路径”。您对您的函数设置了限制,即路径必须都以“/”开头,或者两者都不能。

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

Some developers will want to remove the no-op but that would mean negating the conditional:

一些开发人员会想要删除无操作,但这意味着否定条件:

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

Now -in my opinion- its not so clear from the if-clause the conditions in which you'd want to skip doing the function. To eliminate the no-op and do it clearly, you would want to move the if-clause out of the function:

现在 - 在我看来 - 从 if 子句中不太清楚您想要跳过执行该功能的条件。为了消除空操作并清楚地做到这一点,您需要将 if 子句移出函数:

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

That looks better, but many times we can't do this; we want the the check to be done inside the function.

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

So how often does this happen? Not very often. Maybe once or twice a year. It happens often enough, that you should be aware of it. I don't shy away from using it when I think it improves the readability of my code (regardless of the language).

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

回答by ekkis

suppose you have a command you wish to chain to the success of another:

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

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

but now you want to execute the commands conditionally and you want to show the commands that would be executed (dry-run):

但是现在您想有条件地执行命令,并且想显示将要执行的命令(试运行):

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

so if you set DEBUG and NOEXEC, the second command never shows up. this is because the first command never executes (because NOEXEC is not empty) but the evaluation of that fact leaves you with a return of 1, which means the subordinate command never executes (but you want it to because it's a dry run). so to fix this you can reset the exit value left on the stack with a noop:

所以如果你设置了 DEBUG 和 NOEXEC,第二个命令永远不会出现。这是因为第一个命令永远不会执行(因为 NOEXEC 不为空),但对该事实的评估使您返回 1,这意味着从属命令永远不会执行(但您希望它执行,因为它是空运行)。所以要解决这个问题,您可以使用 noop 重置堆栈中剩余的退出值:

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