1. 程式人生 > 其它 >bash 教程 shell 模式擴充套件 [MD]

bash 教程 shell 模式擴充套件 [MD]

博文地址

我的GitHub 我的部落格 我的微信 我的郵箱
baiqiantao baiqiantao bqt20094 [email protected]

目錄

目錄

Bash 的模式擴充套件

本文改編自 網道的 Bash 教程,主要為了精簡大量本人不感興趣的內容。

簡介

Shell 接收到使用者輸入的命令以後,會根據空格將使用者的輸入,拆分成一個個詞元(token)。然後,Shell 會擴充套件詞元裡面的特殊字元(~?*[]{}$),擴充套件完成後才會呼叫相應的命令。這種特殊字元的擴充套件,稱為模式擴充套件(globbing)。

Bash 是先進行擴充套件,再執行命令。擴充套件的結果是由 Bash 負責的,與所要執行的命令無關。命令本身並不存在引數擴充套件,收到什麼引數就原樣執行。

模組擴充套件的英文單詞是globbing,這個詞來自於早期的 Unix 系統有一個/etc/glob

檔案,儲存擴充套件的模板。後來 Bash 內建了這個功能,但是這個名字就保留了下來。

模式擴充套件與正則表示式的關係是:模式擴充套件的出現早於正則表示式,可以看作是原始的、早期的、低配版正則表示式,它的功能沒有正則那麼強大靈活,但是優點是簡單和方便。

set -f  # 【set -o noglob】關閉擴充套件
set +f  # 【set +o noglob】開啟擴充套件

檔名擴充套件

檔名擴充套件字元只有 檔案存在 的前提下才會擴充套件,如果不存在可匹配的檔名,就會原樣輸出。

使用者主目錄 ~

波浪線~會擴充套件成當前使用者的主目錄。

echo ~      # 【/home/bqt】波浪線 ~ 會擴充套件成當前使用者的主目錄
echo ~/foo  # 【/home/bqt/foo】主目錄的某個子目錄
echo ~root  # 【/root】使用者 root 的主目錄
echo ~foo   # 【~foo】如果使用者名稱 foo 不存在,就會原樣輸出
echo ~+     # 擴充套件成當前所在的目錄,等同於【pwd】命令

單個字元 ?

字元?代表檔案路徑裡面的任意單個字元,不包括空字元。

ls ?.txt    # 【a.txt】字元 ? 代表檔案路徑裡面的任意單個字元,不包括空字元
ls ??.txt   # 【ab.txt】如果匹配多個字元,就需要多個 ? 連用
echo ?.bqt  # 【?.bqt】如果不存在可匹配的檔名,就會原樣輸出

任意字元 *

字元*代表檔案路徑裡面的任意數量的任意字元,包括零個字元。*不會匹配以.開頭的隱藏檔案

echo *.txt   # 【a.txt ab.txt】字元 * 代表檔案路徑裡面的任意數量的任意字元,包括零個字元
echo *       # 輸出當前目錄所有檔案,不包括以 . 開頭的隱藏檔案,不包括子目錄中的檔案
echo *.bqt   # 【*.bqt】如果不存在可匹配的檔名,就會原樣輸出

echo .*      # 輸出當前目錄所有隱藏檔案(即以 . 開頭的檔案)
echo .[!.]*  # 輸出當前目錄所有隱藏檔案,同時排除 .(當前目錄)和 ..(上級目錄)這兩個隱藏檔案

*只匹配當前目錄,不會匹配子目錄

echo */      # 輸出當前目錄所有子目錄
echo */*     # 輸出當前目錄所有子目錄中的所有檔案
echo */*/    # 輸出當前目錄所有二級子目錄
echo */*/*   # 輸出當前目錄所有二級子目錄中的所有檔案,有幾層子目錄,就必須寫幾層星號

開啟 globstar 引數以後,** 可以匹配零個或多個任意深度子目錄(Bash 4.0 中新增)

shopt globstar    # 查詢某個引數關閉還是開啟,globstar 引數預設是關閉的
shopt -s globstar # 開啟某個引數,開啟 globstar 引數以後,** 可以匹配零個或多個子目錄
shopt -u globstar # 關閉某個引數
echo **/*         # 輸出當前目錄以及【任意深度子目錄】中的所有檔案

任一字元 []

  • 方括號擴充套件 [...] 可以擴充套件任意一個括號之中的字元
  • 排除模式 [^...][!...] 可以擴充套件任意一個不在方括號中的字元
  • 如果需要匹配字元 [,可以放在方括號內任意位置,不支援匹配字元 ]
  • 如果需要匹配字元 -,只能放在方括號內部的開頭或結尾
echo [ab].txt  # 方括號擴充套件 [...] 可以擴充套件任意一個括號之中的字元
echo [^ab]     # 等價於 [!ab],表示擴充套件任意一個不在方括號中的字元
echo [[ab]     # 如果需要匹配字元 [,可以放在方括號內任意位置,不支援匹配字元 ]
echo [-ab]     # 如果需要匹配字元 -,只能放在方括號內部的開頭或結尾
echo [ab].bqt  # 【[ab].bqt】如果不存在可匹配的檔名,就會原樣輸出

方括號擴充套件有一個簡寫形式[start-end],表示匹配一個連續的範圍。

  • [a-z]:所有小寫字母的字元
  • [!a-z]:所有非小寫字母的字元
  • [a-zA-Z]:所有小寫字母 + 大寫字母
  • [a-zA-Z0-9]:所有小寫字母 + 大寫字母 + 數字
  • program.[co]:檔案program.c與檔案program.o
  • BACKUP.[0-9][0-9][0-9]:所有以BACKUP.開頭,後面是三個數字的檔名

字元類 [[:class:]]

[[:class:]] 表示一個字元類,擴充套件成某一類特定字元之中的一個。

  • [[:digit:]]:匹配任意數字 0-9
  • [[:lower:]]:匹配任意小寫字母 a-z
  • [[:upper:]]:匹配任意大寫字母 A-Z
  • [[:alpha:]]:匹配任意英文字母
  • [[:alnum:]]:匹配任意英文字母與數字
  • [[:cntrl:]]:ASCII 碼 0-31 的不可列印字元
  • [[:print:]]:ASCII 碼 32-127 的可列印字元
  • [[:punct:]]:標點符號(除了 A-Z、a-z、0-9 的可列印字元)
  • [[:graph:]]:匹配任意英文字母、數字、標點符號
  • [[:blank:]]:空格和 Tab 鍵
  • [[:space:]]:空格、Tab、LF(10)、VT(11)、FF(12)、CR(13)
  • [[:xdigit:]]:匹配16進位制字元(A-F、a-f、0-9)
echo [[:upper:]]*  # 輸出所有以大寫字母開頭的檔名
echo [![:digit:]]* # 輸出所有不以數字開頭的檔名
echo [[:blank:]]*  # 【[[:blank:]]*】如果不存在可匹配的檔名,就會原樣輸出

量詞語法 ?+*!@()

量詞語法用來控制模式匹配的次數。它只有在 Bash 的 extglob 引數開啟的情況下才能使用,不過一般是預設開啟的。

shopt extglob     # 查詢某個引數關閉還是開啟,extglob 引數預設是開啟的
shopt -s extglob  # 開啟某個引數,開啟 extglob 引數以後,可以使用量詞語法
shopt -u extglob  # 關閉某個引數
  • ?(pattern-list):匹配零個或一個模式
  • *(pattern-list):匹配零個或多個模式
  • +(pattern-list):匹配一個或多個模式
  • @(pattern-list):只匹配一個模式
  • !(pattern-list):匹配給定模式以外的任何內容
ls abc?(def)       # 【abc abcdef】匹配以 abc 開頭、且以零個或一個 def 結尾的檔案
ls abc+(.txt|.php) # 【abc.php abc.txt】匹配以 abc 開頭、且以 .txt 或 .php 結尾的檔案
ls abc+(.txt)      # 【abc.txt abc.txt.txt】匹配以 abc 開頭、且以 .txt 結尾的檔案
ls a!(b)c.txt      # 【aac.txt ac.txt】匹配除了 abc.txt 以外,以 a 開頭、且以 c.txt 結尾的檔案
echo abc*(.bqt)    # 【abc*(.bqt)】如果不存在可匹配的檔名,就會原樣輸出

字串擴充套件

所有值 {}

大括號擴充套件 {...} 表示分別擴充套件成大括號裡面的所有值。

  • 各個值之間使用逗號分隔,值可以是多字元的模式
  • 逗號前面可以沒有值,表示擴充套件的第一項為空
  • 逗號前後不能有空格,否則,Bash 會認為這不是大括號擴充套件,而是獨立的引數
  • 大括號可以巢狀,可以與其他模式聯用,並且總是先於其他模式進行擴充套件
  • 大括號擴充套件不是檔名擴充套件,它總是會擴充套件的,這與方括號擴充套件 [...] 完全不同
echo {1,2,3}          # 【1 2 3】大括號擴充套件 {...} 表示分別擴充套件成大括號裡面的所有值
ls {,a,abc}.txt       # 依次訪問 .txt a.txt abc.txt 三個檔案,而不管檔案是否存在
echo a{a{1,2},b{3,4}} # 【aa1 aa2 ab3 ab4】支援巢狀
echo /bin/{cat,ba*}   # 大括號也可以與其他模式聯用,並且總是先於其他模式進行擴充套件

大括號擴充套件可直接用於for迴圈。

for i in {1,2,4,白乾濤}
do
  echo $i
done
  • 大括號擴充套件的簡寫形式 {start..end} 表示擴充套件成一個連續序列
  • 大括號擴充套件另一個簡寫形式 start..end..step 可指定擴充套件的步長
  • 簡寫形式支援逆序、支援巢狀
echo {01..5}          # 【01 02 03 04 05】擴充套件成一個連續序列
echo {0..8..2}        # 【0 2 4 6 8】可指定擴充套件的步長
echo {a..c}{1,2}      # 【a1 a2 b1 b2 c1 c2】多個簡寫形式連用,會有迴圈處理的效果
echo .{mp{5..3},mkv}  # 【.mp5 .mp4 .mp3 .mkv】支援逆序,支援巢狀
echo {a1..3c}         # 【{a1..3c}】遇到無法理解的簡寫時會原樣輸出,不會擴充套件

美元符號擴充套件

變數擴充套件 $

Bash 將美元符號$開頭的詞元視為變數,將其擴充套件成變數值。${!string*}${!string@}返回所有匹配給定字串string的變數名。

echo $SHELL   # 【/bin/bash】
echo ${SHELL} # 【/bin/bash】變數名也可以放在 ${} 裡面
echo ${!S*}   # 返回所有以 S 開頭的變數名,如果不存在,則返回空

子命令擴充套件 $(...)

$(...) 可以擴充套件成另一個命令的執行結果,該命令的所有輸出都會作為返回值。

echo $(date)       # 返回 date 命令的執行結果,注意 date 是一個命令而非一個變數
echo `date`        # 將子命令放在反引號之中,也可以擴充套件成命令的執行結果
echo $(ls $(pwd))  # 子命令擴充套件可以巢狀

算術擴充套件 $((...))

$((...)) 可以擴充套件成整數運算的結果。

echo $((2 + 2))  # 4

模式擴充套件相關的 shopt 命令

shopt命令可以調整 Bash 的行為。它有好幾個引數跟萬用字元擴充套件有關。

shopt [optionname]    # 查詢某個引數關閉還是開啟
shopt -s [optionname] # 開啟某個引數
shopt -u [optionname] # 關閉某個引數
  • dotglob:預設關閉,可以讓擴充套件結果包括隱藏檔案,即以點開頭的檔案。
  • nullglob:預設關閉,可以讓萬用字元不匹配任何檔名時,返回空字串而非原樣返回
  • failglob:預設關閉,可以讓萬用字元不匹配任何檔名時,直接報錯,而非繼續讓各個命令去處理。
  • extglob:預設開啟,可以讓 Bash 支援 ksh 的一些擴充套件語法。它的主要應用是支援量詞語法
  • nocaseglob:預設關閉,可以讓萬用字元擴充套件不區分大小寫。
  • globstar:預設關閉,可以讓 ** 匹配零個或多個子目錄(Bash 4.0 中新增)。

模式擴充套件使用注意點

  • 萬用字元是先解釋,再執行:Bash 接收到命令以後,如果發現裡面有萬用字元,會先進行萬用字元擴充套件,然後再執行命令。
  • 檔名擴充套件在沒有可匹配的檔案時,會原樣輸出。
  • 所有檔名擴充套件只匹配單層路徑,無法匹配子目錄裡面的檔案(即:不能匹配路徑分隔符/)。
  • Bash 允許檔名使用萬用字元,即檔名包括特殊字元。這時引用檔名,需要把檔名放在單引號或雙引號裡面。

2022-1-2

本文來自部落格園,作者:白乾濤,轉載請註明原文連結:https://www.cnblogs.com/baiqiantao/p/15758543.html