Linux命令行下 " ! " 的幾個用法
!
在大多數編程語言中表示取反的意思,但是在命令行中,他還有一些其他的神奇用法。熟練掌握這些用法,可以大大提高我們日常命令行操作的效率。
1 執行歷史命令
!!
!
在命令行中可以用來執行歷史命令,最常用的,大家應該比較熟悉的是執行上一條命令 !!
,它可以用來執行最近的一條命令。
該命令在我們忘記使用 root 權限執行某項命令時很有用:sudo !!
在上一條命令之前加 root 權限再執行。
比如,我們要用 fdisk
命令查看磁盤信息,但是如果沒有 root 權限是會被拒絕的,這時我們就可以直接 sudo !!
:
$ fdisk -l
fdisk: cannot open /dev/loop0: Permission denied
# ...
fdisk: cannot open /dev/loop30: Permission denied
fdisk: cannot open /dev/loop31: Permission denied
$ sudo !!
sudo fdisk -l
[sudo] password for song:
Disk /dev/loop0: 4.2 MiB, 4448256 bytes, 8688 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
# ...
或者在我們忘記加某項參數時,也可以通過 !! -p
來快速添加參數執行上一條命令。比如我要 gdb 調試某個源文件,但是忘了加 -g
參數,即可:
g++ quickSort.cpp
!! -g
有趣的是,!!
符號可以理解為完整地重復上一條指令的文本,即使在有些時候語義不連貫也是可行的。比如下面這個情景。
在當前目錄下,我們有 tsne.py 和 tsne.png 兩個文件,這時我想要 vim 修改 tsne.py 的內容,很有可能會手快通過 tab 鍵執行這樣的命令:vim tsne.p
,這時我們可以直接 !!y
,就能順利地執行 vim tsne.py
。
!n
!!
命令雖然很好用,但是它只能執行上面最近一條命令,那么能不能執行上面幾條(如倒數第二條、倒數第三條)指令呢,又能不能有一個一般的命令,來執行某一條歷史命令呢?當然是有的!
首先,我們知道 history
命令可以查看最近的歷史命令。值得注意的是,它顯示的每條歷史命令之前會有一個編號,我們好像在平常沒太注意過這個編號有什么作用:
$ history2083 ls2084 vim quickSort.cpp2085 g++ quickSort.cpp2086 g++ quickSort.cpp -g2087 history
實際上,我們可以直接通過這個編號來執行某條歷史命令,如 !2084
。
這個用法好像比較雞肋,因為歷史命令編號我們很少回去記住它,每次要用 history
命令查,再執行的話未免有些麻煩。筆者一時能想到的應用場景是如果我們在一段時間(比如一小時、一下午)內,要重復的用某條超復雜的命令(比如很長的路徑名),我們不妨短時記憶一下某個歷史命令編號,并多次使用該編號執行歷史命令。
比如我今天下午調試程序時要多次修改某個 py 文件,就可以記住這個命令的編號,然后每次 !1994
來執行歷史命令。
1994 vim /home/ps/JJ_Projects/ssl_transformer_aes/my_project/SiT/pretrain_ssl.sh
!-i
!-i
的形式可以執行倒數第 i 條命令。如 !-6
,!-8
等。特別地,!-1
就相當于 !!
。
!cmd
!cmd
通過關鍵詞來執行歷史命令。可以按照下面的命令來理解:
$ ls /home > /dev/null
$ ls -l /home/song/JJ_Projects/ > /dev/null
$ ls -la /home/song/JJ_Projects/ > /dev/null
$ ls -lA /usr/bin > /dev/null
上面是相同的ls命令對應了不同參數和文件夾。此外我們將每一個標準輸出都傳遞到了 /dev/null 因為我們并不希望處理程序的標準輸出。現在我們可以調用命令的關鍵詞來實現它們。
$ !ls
$ !ls -l
$ !ls -la
$ !ls -lA
當你使用 !ls
關鍵詞來執行之前命令的時候,你一定會被標準輸出給驚訝到。
2 復用歷史參數
!$和!^
如同 !!
來執行上一條命令一樣,!$
和 !^
也是很常用的,它們的作用是重復上一條命令的第一個或最后一個參數。
以 !$
為例,考慮這樣的場景,我要刪除某個目錄下的所有 png 圖像文件,但是在刪除之前,我要先查看一下,確定這些圖像文件確實都是沒有用的。可以這樣操作:
ls /home/song/JJ_Projects/ava-mlsp/metadata/*.png
rm !$
這樣能省去我們重復上一個命令操作參數的時間。
另一個更普遍的場景:當我們編輯完 ~/.bashrc
文件后,需要用 source
命令使它生效,此時可以:
vim ~/.bashrc
# 一頓操作,修改 .bashrc 文件內容
source !$
!cmd:n
同樣的,我們將 !$
和 !^
推廣到一般情況,!cmd:n
:獲取最近一次 cmd
命令的第 n 個參數(參數的個數從 0 開始計)。
如:
ls -a -l
ls !ls:1
這樣后面一條命令相當于執行了:ls -l
。
3 取反
!
在很多編程語言中都是取反的意思,!=
也通常都是不等于的意思。
在邏輯判斷中取反
同大多數編程語言一樣,!
在 shell 腳本中表示取反的意思。
如 [ ! -d /home/song/JJ_Prjects ]
可以用來判斷該目錄是否為空。
在命令中取反
如 rm !(train.py)
可以刪除當前目錄下除了 train.py 之外的全部文件。rm !(*.png)
刪除當前目錄下除了后綴名為 png 之外的全部文件。
總結起來最常用的除了在編程時取反之外,在命令行中用起來比較絲滑的也就是 !!
和 !$
,它們的推廣的更一般的形式雖然能實現的功能更全面,但稍顯麻煩,不太常用。以上就是筆者對 !
在命令行中使用的總結了,如果有錯誤或補充,歡迎留言討論。
Ref:
https://linuxstory.org/mysterious-ten-operator-in-linux/