我在bash中搜索了noop (:), 但没有找到任何有用的信息。这个运算符的确切目的或用例是什么?
我尝试了以下内容,对我来说它起作用了:
[mandy@root]$ a=11
[mandy@root]$ b=20
[mandy@root]$ c=30
[mandy@root]$ echo $a; : echo $b ; echo $c
10
30
请让我知道,在实时中这个运算符的任何使用情况,或者任何必须使用它的地方。
出于历史原因,它还在那里。 冒号内置 :
与 true
完全等效。 在返回值很重要的情况下,例如在无限循环中,使用 true
是传统的做法:
while true; do
echo 'Going on forever'
done
在 shell 语法要求有命令但你没有要执行的操作时,使用 :
是传统的做法。
while keep_waiting; do
: # busy-wait
done
:
内置命令可以追溯到汤普森壳层,现在在Unix v6中存在。 :
是汤普森shell的goto
语句的标签指示器。标签可以是任何文本,因此:
也充当注释指示器(如果没有goto comment
,那么: comment
实际上是注释)。Bourne shell没有goto
但保留了:
。
:
,即: ${var=VALUE}
,如果未设置,则将var
设置为VALUE
,如果var
已经设置,则不做任何操作。这个结构只存在于变量替换的形式中,并且这个变量替换需要以某种方式成为命令的一部分:一个无操作的命令可以很好地服务。#
作为注释(或者#!/bin/sh
shebangs); :
命令引入了注释,并且对于在其注释中制作了一个漂亮的星星盒子的天真程序员来说是个不幸的事情:: ****
(或者更糟糕的是,: * * *
)。 - Jonathan Leffler:
是一个命令,所以在发现 :
忽略它们之前,shell 仍然需要处理它的参数。大多数情况下,你只是让 shell 在将 *
扩展成当前目录中的文件列表方面做了额外的工作;这实际上不会影响脚本的运行方式。 - chepnerset -e
时才会出现这种情况。无论如何,希望我们都可以同意使用#
:) - Jack O'Connorwhile : ; do ... ; done
来创建一个快速而简单的无限循环。(通常在循环中会有一个 sleep
,我会使用 Ctrl-C 来终止它。) - Keith Thompson我在注释掉所有代码时使用它来进行if语句。例如,您有一个测试:
if [ "$foo" != "1" ]
then
echo Success
fi
但是您想临时注释掉其中包含的所有内容:
if [ "$foo" != "1" ]
then
#echo Success
fi
导致bash显示语法错误的原因:
Which causes bash to give a syntax error:
line 4: syntax error near unexpected token `fi'
line 4: `fi'
Bash无法有空块(WTF)。 因此,您需要添加一个空操作符: if [ "$foo" != "1" ]
then
#echo Success
:
fi
或者您可以使用no-op来注释掉这些行:
if [ "$foo" != "1" ]
then
: echo Success
fi
set -e
,那么|| :
是一个很好的方法,可以在脚本发生失败时不会退出(它明确地使其通过)。||:
,然后稍后使用exit 0
自己处理错误,将允许您在调试期间将所有stdout和stderr显示到应用程序窗口中。考虑{ foo ... 2>&1; } || :
,它比设置更复杂的陷阱和if-then要简单得多。 - Beejoralias
参数有时您想要一个不带任何参数的别名。您可以使用:
来实现:
> alias alert_with_args='echo hello there'
> alias alert='echo hello there;:'
> alert_with_args blabla
hello there blabla
> alert blabla
hello there
#
来实现相同的效果。 - Zoey Hewll#
将会使得在同一行中语法上后面的所有内容都被忽略。这与其他情况(例如考虑 my_alias arg ; other_command
或者 my_alias arg1 {BACKSLASH}{NEWLINE} arg2
)有很大区别,并且可能会导致语法错误(猜猜 while my_alias ; do true ; done
或者 while true ; do my_alias ; done
会做什么)。 - Maëlanset -x
运行shell时,我们永远不会看到#
后面的内容。 - Ярослав Рахматуллин您可以使用:
来提供一个成功但不执行任何操作的命令。在这个例子中,“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
$(verbosity $i)
在某些情况下什么也不做。 - Lightness Races in Orbit其中一种用途是作为多行注释,或者与此文件结合使用,将代码的一部分注释掉以进行测试。
: << 'EOF'
This part of the script is a commented out
EOF
别忘了在EOF
周围使用引号,这样里面的任何代码都不会被执行,比如$(foo)
。也许值得使用一个直观的终止符名称,比如NOTES
、SCRATCHPAD
或TODO
。
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
}
[ -z "$NOEXEC" ] && $cmd || :
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
一些开发者可能想要移除无操作,但这意味着需要否定条件:
function chgpath() {
# toC, fromC are the first characters of the argument paths.
if [[ "$toC" != / || "$fromC" == / ]] && [[ "$toC" == / || "$fromC" != / ]]
then
return 1 # Skip function.
fi
在我看来,从if子句中并不清楚你想要跳过执行函数的条件。为了消除无操作并使其更加明确,您需要将if子句移出函数:
if [[ "$toC" == / && "$fromC" == / ]] || [[ "$toC" != / && "$fromC" != / ]]
then
cdPath=$(chgPath pathA pathB) # (we moved the conditional outside)
看起来好多了,但很多时候我们不能这样做;我们希望检查在函数内部完成。
那么这种情况有多常见?并不是很常见。也许一年或两年才会出现一次。它发生的足够频繁,您应该意识到它。我在认为它可以提高代码的可读性时(无论使用何种语言),都不会回避使用它。
: ${...=...}
可以说比 true ${...=...}
看起来更不拘束。有些人可能也更喜欢使用 while :; do
而不是 while true; do
,因为它更简洁。 - chepner和这个答案有些相关,我发现这个 no-op 对于编写多语言脚本非常方便。例如,以下是一个适用于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"
)。更重要的是,它使程序移动或分发更加方便。
A common example. There is a well-known, long-standing issue with shebangs: most systems (including Linux and Cygwin) allow only one argument 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 extenso in some configuration file, then make Vim read that file with -S "/path/to/file"
. Hence I ended up with a polyglot bash/vimscript file.
我的两个。
:
的一个相当奇特的应用是在bash脚本中嵌入POD注释,以便可以快速生成man页面。当然,最终会重写整个Perl脚本 ;-)
这是一种在运行时绑定函数的代码模式。例如,有一个调试函数只在设置了某个标志时才执行某些操作:
#!/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
:
内置命令在 Bourne Shell、KSH 和 Bash 中都存在。 - ghoti:
。 - choroba