Bash 中为 _ 变量赋空值的三个场景

时间:2022-01-12 08:19:26

$_ 有好几个功能,我们最常用的是用它来获取“刚刚执行过的命令的最后一个参数”这个功能,比如下面这样:

$ ls ~/Downloads/very/long/dir/  # ls 到某个目录看看有没有我们想要的文件

file1 file2 needed_file

$ cd $_ # 如果有,就进入到那个文件夹,$_ 让你省去了不少键盘敲击数

Bash manual 中对 $_ 的这个功能的描述只有一句话:

expands to the last argument to the previous command, after expansion.

惜字如金,让你觉的这个功能真的很简单,但稍微深入想一想,如果上次执行的命令完全没有参数呢?

$ echo # 没有参数

$ echo $_

echo

哦哦,这下我们知道了,如果一个参数也没有,那么 $_ 就是命令的名字本身。那么问题又来了,如果命令的名字也没有呢?有些同学就问了,怎么写出一个连命令名也没有的命令呢。其实在 Shell 里面,一条简单命令的组成文法大概是这个样子的:

赋值语句 命令名和参数 重定向

比如 foo=1 bar baz >qux 就是三个部分都存在的命令,但其实,这个三个部分只要存在一个部分就算是一条简单命令了,不信我们试试:

$ foo=1 # 只有第一部分,这也是一条命令,很熟悉吧,就是我们常见的赋值语句

$ foo=1 > bar # 没有第二部分,这也可以

$ >bar # 只有第三部分,还可以

下面就说结论了:当没有命令名和参数这一部分的时候,Bash 会给 _ 赋空值:

$ : foo

$ echo $_ # _ 的值是 foo

foo

$ foo=1

$ echo "左边$_右边" # _ 的值被 Bash 赋值为空,这种情况在 zsh 下只是不更新 _ 的值,还是 foo,但不会赋空值

左边右边

$ : foo

$ > bar

$  echo "左边$_右边" # 同样,又被赋值为空,zsh 下还会是 foo

左边右边

除了这种没有命令名和参数的场景,还有两种情况下 Bash 会给 _ 赋空值,一个是包含管道的命令,再一个是后台(异步)执行的命令:

$ : foo

$ echo 1 | echo 2

2

$ echo "左边$_右边" # _ 为空,在 zsh 下会是最后一个管道右边的命令的最后一个参数,也就是 2

左边右边

$ echo 1 &

$ echo "左边$_右边" # _ 还是空,在 zsh 下没有特殊处理,是 1

左边右边

还有一个 Bash 文档没明确指出的点,那就是只有简单命令才会更新 _ 的值,管道命令,命令列表,复合命令这些命令本身,都不会更新 _ 的值,但它们包含的简单命令要是执行了的话是会影响的(比如 for 循环里的简单命令没有执行的话,不会更新 _,反之亦然)。