感嘆號:bash 的歷史擴充套件功能
Bash 的歷史擴充套件(History Expansion)又被稱為 Bang(!) 命令,歷史擴充套件是 bash 將歷史命令轉換到可執行命令的過程。Bash 下的 History 庫提供了一個與 csh 下歷史擴充套件類似的歷史擴充套件功能。歷史擴充套件中操作歷史命令一般有兩個部分:
- 首先要從歷史命令中找出相對應的命令,被選擇到的命令我們稱作為Event(條目),比如Bang Bang(!!),就是選擇最後一條命令;
- 選擇選定行的部分或全部文字以包含到當前行中。要操作的條目(Event)Bash將其拆分成了Words(詞),命令中的Words是靠空格來分割的,我們就可以使用修飾符(Modifiers)來調整Words以符合我們的要求。注意:Words並不是英文單詞,而是一個字元序列而已。
先來看兩個命令,你知道第二個命令是什麼意思麼?
cat /tmp/cat.cat.txt !:0 !*:gs/cat./echo.
條目標誌符(Event Designators)
條目標誌符是一個到歷史列表內一個命令列實體的引用,除非是絕對引用,不然條目的引用是相對歷史列表中當前位置的。
條目標誌符 | 條目標誌符說明 |
---|---|
! | 開始一個歷史替換,除非後面緊跟的是空格,製表符,行結束符,”=”,”(“(當使用內建命令shopt開啟了extglob的shell選項)。 |
!n | 重複歷史中編號為n的命令——歷史編號可以參看history命令. |
!-n | 執行之前的第n條命令,執行上一條命令可以使用!!或者!-1,執行之前第三條命令:!-3,倒推的列表是history。 |
!! | 執行上一條命令,和Ctrl-P,!-1的作用一樣。 |
!string | 執行最近的以string字串開頭的命令。這個命令的意思是重複以!後字串開頭的最後一條命令,比如:!ca將重複以字元ca開頭的最後一條命令,如cat ReadMe,(假設最近一條ca開頭是這個命令,並且ReadMe後緊跟換行符) |
!?string[?] | 在歷史列表中以當前位置開始向後查詢(往回搜尋)包含string字串的最近一條命令,如果要查詢的string字串後面緊跟換行符,則string後面的這個問號可以省略。例如:!?Read?還是會匹配cat ReadMe。(同上的環境),如果後面是換行符如:!?ReadMe,則不用輸入結尾的[?]。 |
^a^b | 快速替換,把上一條命令中的a替換成b,並執行替換後的命令。^a^b^類似。注意:這裡只是替換一個找到的例項,相當於:!!:s/a/b。 |
^abc | 刪除上一條命令中的abc。 |
!# | 引用目前輸入的所有字串,如:more a !#;這個最終的命令是more a more a。 |
詞標誌符(Word Designators)
詞標誌符被用來在條目裡面選擇需要的詞。一般用”:”分隔條目指示符和詞指示符。當詞指示符是以”^”,”$”,”*”,”-”,”%”開頭時,也可能會省略”:”。詞是從一行的行首開始,第一個詞編號為0.插入到當前行中時,這些詞使用單個空格分隔。
詞標誌符 | 詞標誌符說明 |
---|---|
0 | 第0個詞,在很多應用程式中,這就是命令本身。 |
n | 第n個詞 |
^ | 第一個引數;也就是第一個詞。 |
$ | 最後一個引數。 |
% | 最近”?string?”匹配的詞。 |
x-y | 詞的範圍:如果是’0-y’可以簡寫成’-y’. |
* | 除了第0個以外的所有詞,這個和’1-$’同義,如果條目中只有一個詞,使用’*'也不會返回錯誤,僅是返回一個空字串而已。 |
x* | ‘x-$’的簡寫 |
x- | 和x*類似,都是’x-$’的簡寫,不過需要注意,這個寫法是忽略最後一個詞的。 |
需要注意的是,在Bash下使用詞指示符的時候,可以沒有條目指示符,如果沒有使用條目指示符,則會把前一條命令作為詞指示符的操作條目。
修飾符(Modifiers)
在可選的詞指示符之後,你可以新增下面修飾符中的一個或多個,每個修飾符以’:'開頭。
修飾符 | 修飾符說明 |
---|---|
h | 去掉路徑名的尾部,只保留頭部。只移除最後一個’/'後面的內容,可以理解成是路徑名的父目錄。 |
t | 去掉路徑名部件中除尾部之外的所有內容。只保留最後一個’/'後的內容。 |
r | 去掉尾部這樣格式”.suffix”的一個結尾字尾,保留基本名稱。只刪除最後一個點’.'後的內容。 |
e | 僅保留字尾。僅保留最後一個點’.'及點後的內容。 |
p | 列印新的命令但不執行。 |
q | 引用替換的詞,防止進一步替換。(譯註,原文:Quote the substituted words, escapin further substitutions.——Mitchell Chu)。這個引用會直接對引用的命令加上單引號,防止進一步替換。開始這句不知道怎麼翻譯。後來Mitchell發現自己的這個翻譯並沒有錯誤,因為我們引用的詞可能是個變數,這時候如果沒有引號,就會引起進一步的替換,而是用此引數就能達到防止這種情況的發生。 |
x | 這個和q一樣,是引用替換的詞,但是這個與q不同的地方在於,q是整體引用,而這個是會將替換的詞使用空格,製表符,換行符來分割成一個個的詞。 |
s/old/new/ | 把條目行中找到的第一個old位置的內容替換成new位置的內容,’/'這個分隔符位置可以使用任何其他字元作為分隔符。如果要在old或new位置使用分隔符,需要使用反斜杆’/'來轉義。如果’&’這個字元出現在new位置,將會被替換成old位置的內容,如果要使用’&’請用’/'轉義。最後一個分隔符如果是整行的最後一個字元,則可以省略。 |
& | 重複上次替換。這個是引用最後一次的s/old/new/內容。 |
g | 見下,與a相同 |
a | 使替換在整個條目中進行,和’s'一起使用,例如:!!:gs/old/new/,或者和’&’一起使用。 |
G | 對條目中的每一個詞都執行一次其後的’s'修飾符。這個方法在Bash 4.1.2下測試並不靠譜。
test $eee /tmp/test.log echo !test:Gs/t/a/; ## 這個返回的test被替換兩次 ## 但後面的引數僅替換一次 因此Mitchell在想,是不是僅對引數執行一次,而對命令(第0個詞)進行全域性替換。但另外一個測試,反駁了這個觀點: aaaaaaaaaaa $aaaaaaa /tmp/aaaaaaaaaaaaa.log echo !aaaa:q:Gs/a/t/ ## 此時,最多的替換出現在!:0,兩次! 但多次測試結果來看,第零個詞彙被替換最多兩次,其他只替換一次。具體原因暫時未知! |
瞭解了這些,我們來揭曉一下文章開頭的命令的意義:
- 我們首先是選出命令!!(!:0可以寫成!!:0,!*同樣可以寫成!!*)
- 有了命令之後我們選擇第二步,利用0,選擇出詞(!:0選擇出來的是cat)
- 第三步是對詞進行操作,這裡是!*後面對引數進行了字元替換。
- 最後變成完成的命令了: cat /tmp/echo.echo.txt
(注:轉載時對原文有修改。)
相關文章
- bash的特有擴充套件屬性套件
- 擴充套件你的KUBECTL功能套件
- 推薦一個 Chrome 瀏覽歷史記錄管理的擴充套件 - History Trends UnlimitedChrome套件MIT
- kotlin 擴充套件(擴充套件函式和擴充套件屬性)Kotlin套件函式
- SpringBoot-11 擴充套件功能Spring Boot套件
- Jmeter——元件擴充套件,使其功能更全面JMeter元件套件
- Eclipse 專案有紅感嘆號Eclipse
- python算術運算子的擴充套件功能Python套件
- 用C語言擴充套件Python的功能C語言套件Python
- win10網路感嘆號怎麼解決_win10網路感嘆號修復方法Win10
- WCF擴充套件:行為擴充套件Behavior Extension套件
- iOS 8.3新功能曝光:WiFi 通話功能擴充套件iOSWiFi套件
- 解決 Eclipse專案紅感嘆號(或×號)Eclipse
- ?用Chrome擴充套件管理器, 管理你的擴充套件Chrome套件
- WPF之花式控制元件功能擴充套件控制元件套件
- 虛擬主機支援哪些擴充套件功能套件
- 擴充套件系統功能——裝飾模式(四)套件模式
- 擴充套件系統功能——裝飾模式(三)套件模式
- 擴充套件系統功能——裝飾模式(二)套件模式
- 【Kotlin】擴充套件屬性、擴充套件函式Kotlin套件函式
- Sanic 擴充套件套件
- ORACLE 擴充套件Oracle套件
- 擴充套件工具套件
- 擴充套件歐幾里得套件
- DOM擴充套件套件
- 擴充套件ACL套件
- Lua擴充套件套件
- 照片擴充套件套件
- 擴充套件篇套件
- disable or 擴充套件套件
- 擴充套件表套件
- Mybatis擴充套件MyBatis套件
- php擴充套件手機號碼歸屬地PHP套件
- Laravel 執行時類的功能擴充套件的實現Laravel套件
- PHP擴充套件開發就是一個自己的PHP擴充套件PHP套件
- 表空間自動擴充套件 AUTOALLOCATE 的擴充套件規律套件
- 正則的擴充套件套件
- SRAM的容量擴充套件套件