在Linux命令列下令人驚歎的驚歎號(!)

linux.cn發表於2015-06-11

‘!’符號在Linux中不但可以用作否定符號,還可以用來從歷史命令記錄中取出命令或不加修改的執行之前執行的命令。下面的所有命令都已經在Bash Shell中經過確切地檢驗。儘管我沒有試過,但大多都不能在別的Shell中執行。這裡我們介紹下Linux命令列中符號’!'那驚人和奇妙的用法。

在Linux命令列下令人驚歎的驚歎號(!)

1. 使用數字從歷史命令列表中找一條命令來執行

您也許沒有意識到您可以從歷史命令列表(之前已經執行的命令集)中找出一條來執行。首先,通過”history”命令查詢之前命令的序號。

$ history

在Linux命令列下令人驚歎的驚歎號(!)

使用history命令找到最後執行的命令

現在,只需要使用歷史命令輸出中顯示在該命令前面的數字便可以執行這個命令。例如,執行一個在history輸出中編號是1551的命令。

$ !1551

在Linux命令列下令人驚歎的驚歎號(!)

使用命令ID來執行最後執行的命令

這樣,編號為1551的命令(上面的例子是top命令)便執行了。這種通過ID號來執行之前的命令的方式很有用,尤其是在這些命令都很長的情況下。您只需要使用![history命令輸出的序號]便可以呼叫它。

2. 執行之前的倒數第二個、第七個命令等

您可以以另一種方式來執行之前執行的命令,通過使用-1代表最後的命令,-2代表倒數第二個命令,-7代表倒數第七個命令等。

首先使用history命令來獲得執行過的命令的列表。history命令的執行很有必要,因為您可以通過它來確保沒有rm command > file或其他會導致危險的命令。接下來執行倒數第六個、第八個、第十個命令。

$ history
$ !-6
$ !-8
$ !-10

在Linux命令列下令人驚歎的驚歎號(!)

通過負數序號執行之前執行的命令

3. 傳遞最後執行的命令的引數,以方便的執行新的命令

我需要顯示/home/$USER/Binary/firefox資料夾的內容,因此我執行:

$ ls /home/$USER/Binary/firefox

接下來,我意識到我應該執行’ls -l’來檢視哪個檔案是可執行檔案。因此我應該重新輸入整個命令麼?不,我不需要。我僅需要在新的命令中帶上最後的引數,類似:

$ ls -l !$

這裡!$將把最後執行的命令的引數傳遞到這個新的命令中。

在Linux命令列下令人驚歎的驚歎號(!)

將上一個命令的引數傳遞給新命令

4. 如何使用!來處理兩個或更多的引數

比如說我在桌面建立了一個文字檔案file1.txt。

$ touch /home/avi/Desktop/1.txt

然後在cp命令中使用絕對路徑將它拷貝到/home/avi/Downloads。

$ cp /home/avi/Desktop/1.txt /home/avi/downloads

這裡,我們給cp命令傳遞了兩個引數。第一個是/home/avi/Desktop/1.txt,第二個是/home/avi/Downloads。讓我們分別處理他們,使用echo [引數]來列印兩個不同的引數。

$ echo "1st Argument is : !^"
$ echo "2nd Argument is : !cp:2"

注意第一個引數可以使用”!^”進行列印,其餘的命令可以通過”![命令名]:[引數編號]“列印。

在上面的例子中,第一個命令是cp,第二個引數也需要被列印。因此是”!cp:2″,如果任何命令比如xyz執行時有5個引數,而您需要獲得第四個引數,您可以使用”!xyz:4″。所有的引數都可以通過”!*”來獲得。

在Linux命令列下令人驚歎的驚歎號(!)

處理兩個或更多的引數

5. 以關鍵字為基礎執行上個的命令

我們可以以關鍵字為基礎執行上次執行的命令。可以從下面的例子中理解:

$ ls /home > /dev/null                      [命令1]
$ ls -l /home/avi/Desktop > /dev/null                       [命令2]   
$ ls -la /home/avi/Downloads > /dev/null                    [命令3]
$ ls -lA /usr/bin > /dev/null                       [命令4]

上面我們使用了同樣的命令(ls),但有不同的開關和不同的操作資料夾。而且,我們還將輸出傳遞到/dev/null,我們並未顯示輸出,因而終端依舊很乾淨。

現在以關鍵字為基礎執行上個的命令。

$ ! ls                  [命令1]
$ ! ls -l               [命令2]   
$ ! ls -la              [命令3]
$ ! ls -lA              [命令4]

檢查輸出,您將驚奇發現您僅僅使用關鍵字ls便執行了您已經執行過的命令。

在Linux命令列下令人驚歎的驚歎號(!)

以關鍵字為基礎執行命令

(LCTT 譯註:澄清一下,這種用法會按照命令名來找到最後匹配的命令,不會匹配引數。所以上述執行的四個命令都是執行了 ls -lA /usr/bin > /dev/null,並增加了新的引數而已。)

6. !!操作符的威力

您可以使用(!!)執行/修改您上個執行的命令。它將附帶一些修改/調整並呼叫上個命令。讓我給您展示一些實際情境。

昨天我執行了一行指令碼來獲得我的私有IP,因此我執行了:

$ ip addr show | grep inet | grep -v 'inet6'| grep -v '127.0.0.1' | awk '{print $2}' | cut -f1 -d/

接著,我突然發現我需要將上面指令碼的輸出重定向到一個ip.txt的檔案,因此,我該怎麼辦呢?我該重新輸入整個命令並重定向到一個檔案麼?一個簡單的解決方案是使用向上游標鍵並新增’> ip.txt’來將輸出重定向到檔案。

$ ip addr show | grep inet | grep -v 'inet6'| grep -v '127.0.0.1' | awk '{print $2}' | cut -f1 -d/ > ip.txt

在這裡要感謝救世主”向上游標鍵”。現在,考慮下面的情況,這次我執行了下面這一行指令碼。

$ ifconfig | grep "inet addr:" | awk '{print $2}' | grep -v '127.0.0.1' | cut -f2 -d:

一旦我執行了這個指令碼,Bash提示符便返回了錯誤訊息”bash: ifconfig: command not found”。原因並不難猜,我執行了本應以root許可權的執行的命令。

所以,怎麼解決呢?以root使用者登入並且再次鍵入整個命令就太麻煩了!而且向上導航鍵也不管用了(LCTT 譯註:當你以新的使用者身份登入了,是不能用向上游標鍵找到之前的另外一個使用者的命令歷史的)。因此,我們需要呼叫”!!”(去掉引號),它將為那個使用者呼叫上個命令。

$ su -c !! root

這裡su是用來切換到root使用者的,-c用來以某使用者執行特定的命令,最重要的部分是!!,它將被替換為上次執行的命令。當然!您需要提供root密碼。

在Linux命令列下令人驚歎的驚歎號(!)

!!操作符的威力

我通常在下面的情景中使用!!。

當我用普通使用者來執行apt-get,我通常收到提示說我沒有許可權來執行。

$ apt-get upgrade && apt-get dist-upgrade

好吧,有錯誤。但別擔心,使用下面的命令來成功的執行…

$ su -c !!

同樣的適用於:

$ service apache2 start

$ /etc/init.d/apache2 start

$ systemctl start apache2

普通使用者不被授權執行那些任務,這樣相當於我執行:

$ su -c 'service apache2 start'

$ su -c '/etc/init.d/apache2 start'

$ su -c 'systemctl start apache2'

(LCTT 譯註:使用!!之前,一定要確認你執行的是什麼命令!另外,在 root 身份下,千萬不要養成使用它的習慣,因為你總是會在不合適的目錄執行不合適的命令!)

7.執行一個影響所有除了![FILE_NAME]的檔案命令

!(邏輯非)能用來對除了’!'後的檔案的所有的檔案/副檔名執行命令。

A.從資料夾移除所有檔案,2.txt除外。

$ rm !(2.txt)

B.從資料夾移除所有的檔案型別,pdf型別除外。

$ rm !(*.pdf)

8.檢查某個資料夾(比如/home/avi/Tecmint)是否存在?並列印

這裡,我們使用’! -d’來驗證資料夾是否存在,當資料夾不存在時,將使用其後跟隨AND操作符(&&)進行列印,當資料夾存在時,將使用OR操作符(||)進行列印。

邏輯上,當[ ! -d /home/avi/Tecmint ]的輸出為0時,它將執行AND邏輯符後面的內容,否則,它將執行OR邏輯符(||)後面的內容。

$ [ ! -d /home/avi/Tecmint ] && printf '/nno such /home/avi/Tecmint directory exist/n' || printf '/n/home/avi/Tecmint directory exist/n'

9.檢查某資料夾是否存在?如果不存在則退出該命令

類似於上面的情況,但這裡當期望的資料夾不存在時,該命令會退出。

$ [ ! -d /home/avi/Tecmint ] && exit

10.如果您的home資料夾內不存在一個資料夾(比方說test),則建立它

這是指令碼語言中的一個常用的實現,當期望的資料夾不存在時,建立一個。

[ ! -d /home/avi/Tecmint ] && mkdir /home/avi/Tecmint

這便是全部了。如果您知道或偶爾遇到其他值得了解的’!'使用方法,請您在反饋的地方給我們提建議。保持聯絡!

相關文章