Shell 冒号什么都不做。照样使用它即可。
A shell colon does nothing. Use it anyway

原始链接: https://refp.se/articles/your-shell-and-the-magic-colon

Shell 的“空命令”(`:`)是一个内置运算符,除了对其参数进行求值并返回成功状态码外,什么都不做。虽然它看起来毫无用处,但在编写简洁高效的脚本时却是一个强大的工具。 一个主要的用途是参数扩展。通过将空命令与 `${parameter:?word}` 语法结合使用,您可以在一行内验证必要参数并触发描述性的错误消息。它还允许您为变量分配默认值(例如 `: "${DATA_DIR:=/var/data}"`),而不会让 Shell 尝试将结果值当作命令来执行。 除了变量管理之外,冒号的用途非常广泛:它可以用于截断文件、在 `if/else` 语句中充当占位符、通过 `trap` 忽略信号,或创建无限 `while` 循环。使用空命令有助于减少代码冗余并降低拼写错误的风险,是任何 Shell 脚本编写者工具箱中极具价值的补充。

对不起。
相关文章

原文

A shell colon does nothing. Use it anyway.

I've written more shell scripts than I can count, but I still stumble upon tricks that honestly blow my mind far too often than I care to admit. Latest thing that blew my head clean off? The shell colon.

In a land far-far away..

... there was once a far too cold cup of coffee next to a freshly brewed far-too-hot one. Four different terminals where three could have been closed an hour ago, and a shell script which I really (really) did not want to write.

Who would have thought a single colon would be the one to save the day night?

Note: Want your mind blown straight away? See more colons in the limelight.

Checking for required arguments

This is a familiar dance, it's pretty much muscle memory by this point. You have a script, it takes a few arguments, and some of them are mandatory; alright, an if-statement like so many times before:

if [ -z "$1" ]; then
   echo "missing argument, aborting." 1>&2
   exit 1
fi

echo "Hello $1!"

Though.. what if I told you the above four lines could be replaced by just... one?

: "${1:?missing argument, aborting.}"

echo "Hello $1!"
$ bash example.sh
example.sh: line 1: 1: missing argument, aborting.

$ bash example.sh refp
Hello refp!

Parameter expansion and the story of :?

There are two things going on in the previous snippet, and you are correct in identifying that one part is using parameter expansion:

  • The syntax ${name:?diagnostic} checks whether $name is unset or empty — if it is, the diagnostic is printed to stderr and the shell exits with a non-zero status, otherwise;

  • if the variable is set, it is equivalent to $name.

That.. other colon

So that's one colon, but what about that other one, the one who sits alone at the beginning of the line?

  • : is the null command — a builtin that does nothing but evaluate its arguments and discard the result.

  • : is old — it goes all the way back to the 1971 Thompson shell where it doubled as a label and Unix's very first comment marker.

  • : two eyes staring at you in the dark, with love.

More colons in the limelight

Perhaps we have already established that there is more to : than meets the eye, but to prove the real magic of the null-command — here are a few usages that blew my mind.

: "${DATA_DIR:=/var/data}"       
: "${RETRIES:=3}"                
: > error.log                    
: > error.log > access.log       
( : < dataset.json ) && echo YES 
( : >> result.json ) && echo YES 
trap : INT                       
sleep 60                         
set -u                           
: "$DEPLOY_ENV" "$HOST"          
if some-command; then
    :                            
else
    echo "command failed"
fi

Con-colon-sion

So, if you are like me and prefer less typing (gotta go fast) — the null command and parameter expansion are a pair worth studying before your coffee goes cold.

set  : : : : : : : : : : : : : : : : : : : : :

while : colons are more than "${1:?magic}"; do
    echo "$*" && shift
done

Note: The above example is safe to run locally, try it!

Frequently Asked Questions

After reading a few comments online, it seems I skipped over some things worth explaining. I will keep this section updated as questions come up.

  • Why do I need the null-command? Doesn't the expansion happen without the colon?

    The parameter expansion will happen regardless, but without a null-command or similar usage the shell will treat the resulting string as a command to run.

    % ${HELLO:=123}
    zsh: command not found: 123
    

    If we prefix our parameter-expansion with the null-command, the result is discarded, but the expression is still evaluated (setting HELLO to 123).

    % : ${HELLO:=123}
    % echo $HELLO
    123
    
  • Why use the null-command when I could do VAR=${VAR:-default-value}?

    This at its core boils down to personal preference, but using our beloved colon we can shrink the number of potential typos to one (rather than two):

    : "${DATA_DIR:=/var/data}"           
    DATA_DIR="${DATA_DRI:-/var/data}"    
    
联系我们 contact @ memedata.com