在Linux命令行下令人驚嘆的驚嘆號(!)
1. 使用數字從歷史命令列表中找一條命令來執行
您也許沒有意識到您可以從歷史命令列表(之前已經執行的命令集)中找出一條來運行。首先,通過"history"命令查找之前命令的序號。
$ history
使用history命令找到最後執行的命令
現在,只需要使用歷史命令輸出中顯示在該命令前面的數字便可以運行這個命令。例如,運行一個在history
輸出中編號是1551的命令。
$ !1551
使用命令ID來執行最後運行的命令
這樣,編號為1551的命令(上面的例子是top命令)便運行了。這種通過ID號來執行之前的命令的方式很有用,尤其是在這些命令都很長的情況下。您只需要使用![history命令輸出的序號]便可以調用它。
2. 運行之前的倒數第二個、第七個命令等
您可以以另一種方式來運行之前執行的命令,通過使用-1代表最後的命令,-2代表倒數第二個命令,-7代表倒數第七個命令等。
首先使用history命令來獲得執行過的命令的列表。history命令的執行很有必要,因為您可以通過它來確保沒有rm command > file
或其他會導致危險的命令。接下來執行倒數第六個、第八個、第十個命令。
$ history
$ !-6
$ !-8
$ !-10
通過負數序號運行之前執行的命令
3. 傳遞最後執行的命令的參數,以方便的運行新的命令
我需要顯示/home/$USER/Binary/firefox
文件夾的內容,因此我執行:
$ ls /home/$USER/Binary/firefox
接下來,我意識到我應該執行'ls -l'來查看哪個文件是可執行文件。因此我應該重新輸入整個命令么?不,我不需要。我僅需要在新的命令中帶上最後的參數,類似:
$ ls -l !$
這裡!$
將把最後執行的命令的參數傳遞到這個新的命令中。
將上一個命令的參數傳遞給新命令
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"
。所有的參數都可以通過"!*"
來獲得。
處理兩個或更多的參數
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
便執行了您已經執行過的命令。
以關鍵字為基礎執行命令
(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密碼。
!!操作符的威力
我通常在下面的情景中使用!!
。
當我用普通用戶來運行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]的文件命令
!
(邏輯非)能用來對除了'!'
後的文件的所有的文件/擴展名執行命令。
(LCTT 譯註:該功能需要用 shopt 設置 extglob 模式: shopt -s extglob 才行。)
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 existn' || printf 'n/home/avi/Tecmint directory existn'
9.檢查某文件夾是否存在?如果不存在則退出該命令
類似於上面的情況,但這裡當期望的文件夾不存在時,該命令會退出。
$ [ ! -d /home/avi/Tecmint ] && exit
10.如果您的home文件夾內不存在一個文件夾(比方說test),則創建它
這是腳本語言中的一個常用的實現,當期望的文件夾不存在時,創建一個。
[ ! -d /home/avi/Tecmint ] && mkdir /home/avi/Tecmint
這便是全部了。如果您知道或偶爾遇到其他值得了解的'!'
使用方法,請您在反饋的地方給我們提建議。保持聯繫!
via: http://www.tecmint.com/mysterious-uses-of-symbol-or-operator-in-linux-commands/
作者:Avishek Kumar 譯者:wwy-hust 校對:wxy
本文轉載來自 Linux 中國: https://github.com/Linux-CN/archive