Bash 中為 _ 變數賦空值的三個場景

紫雲飛發表於2015-09-07

$_ 有好幾個功能,我們最常用的是用它來獲取“剛剛執行過的命令的最後一個引數”這個功能,比如下面這樣:

$ 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 迴圈裡的簡單命令沒有執行的話,不會更新 _,反之亦然)。

相關文章