1. 程式人生 > >Bash匹配變數值與讀檔案操作

Bash匹配變數值與讀檔案操作

Bash 匹配變數值與讀檔案操作

$(cat file) 與 $(< file) 達成的功能相同,$(< file) 能夠更快執行,也就是說你需要用 $(< file) 來代替 $(cat file),以獲得更好的效能。下面是一個具體的示例:

[[email protected]:22:36:23] ~ $ cat filelist 
./Screenshot from 2018-10-23 20-03-53.png
./Screenshot from 2018-10-22 23-06-20.png
[[email protected]:22:36:26] ~ $ file=$(cat filelist)
[
[email protected]
:22:36:42] ~ $ echo $file ./Screenshot from 2018-10-23 20-03-53.png ./Screenshot from 2018-10-22 23-06-20.png [[email protected]:22:36:44] ~ $ time file=$(cat filelist) [[email protected]:22:37:16] ~ $ file=$(< filelist) [[email protected]:22:37:17] ~ $ echo $file ./Screenshot from 2018-10-23 20-03-53.png ./Screenshot from 2018-10-22 23-06-20.png

如果現在我需要獲取變數中的某些內容,並且一般的變數擴充套件方式無法做到,那麼我們通常會這樣做:

var=$(echo $var | grep ‘pattern’)

這是一種解決思路,將變數內容通過管道傳送給 grep ,使用 grep 來完成匹配工作,然後將匹配到的結果賦值給 var。你也可以使用 awk、sed 來替換 grep。為什麼需要 echo 一個變數的內容呢?這是因為 awk、sed、grep 不能直接處理變數內容,它們面向檔案完成操作。因此這裡首先使用 echo 將變數的值輸出到管道的另一端,以管道的另一端作為 awk、sed、grep 的輸入進行處理就能夠得到需要的結果。

實際上,我們可以不借助其它命令,完全使用 bash 提供的 [[ expression ]] 語句的擴充套件功能來完成我們想要的功能。上面的示例可以修改為如下語句:

[[ $var =~ pattern ]];
var=${BASH_REMATCH[0]}

下面是一個具體的示例:

[[email protected]:21:03:10] ~ $ filename=$(< filelist)
[[email protected]:21:03:20] ~ $ echo $filename
./Screenshot from 2018-10-23 20-03-53.png ./Screenshot from 2018-10-22 23-06-20.png
[[email protected]:21:03:23] ~ $ [[ $filename =~ ".*from" ]]; echo ${BASH_REMATCH[0]}

[[email protected]:21:04:08] ~ $ [[ $filename =~ "*from" ]]; echo ${BASH_REMATCH[0]}

[[email protected]:21:04:19] ~ $ [[ $filename =~ "from" ]]; echo ${BASH_REMATCH[0]}
from
[[email protected]:21:04:22] ~ $ [[ $filename =~ .*from ]]; echo ${BASH_REMATCH[0]}
./Screenshot from 2018-10-23 20-03-53.png ./Screenshot from
[[email protected]:21:04:32] ~ $ [[ $filename =~ '.*from' ]]; echo ${BASH_REMATCH[0]}

[[email protected]:21:04:43] ~ $ [[ $filename =~ ".*from" ]]; echo ${BASH_REMATCH[0]}

[[email protected]:21:04:50] ~ $ pattern=".*from"
[[email protected]:21:05:00] ~ $ echo $pattern
.*from
[[email protected]:21:05:04] ~ $ [[ $filename =~ "$pattern" ]]; echo ${BASH_REMATCH[0]}

[[email protected]:21:05:20] ~ $ [[ $filename =~ $pattern ]]; echo ${BASH_REMATCH[0]}
./Screenshot from 2018-10-23 20-03-53.png ./Screenshot from

上面的示例中存在著幾個問題。當使用單引號或雙引號將 pattern 括起來的時候,括起來的 pattern 將會變為一般字元而非正則表示式元字元,因此匹配不到任何內容。

當我們使用雙引號將變數括起來時,在這種環境中 shell 不展開變數,以引號中的內容作為一般字元來匹配,因此也沒有匹配到內容。

下面是子組匹配的一個示例:

[[email protected]:21:21:19] ~ $ [[ $filename =~ ^\./([A-Z][a-z]*)( ) ]]; echo ${BASH_REMATCH[0]}; echo ${BASH_REMATCH[1]}
./Screenshot
Screenshot
[[email protected]:21:21:22] ~ $ [[ $filename =~ '^\./([A-Z][a-z]*)( )' ]]; echo ${BASH_REMATCH[0]}; echo ${BASH_REMATCH[1]}


[[email protected]:21:21:34] ~ $ [[ $filename =~ "^\./([A-Z][a-z]*)( )" ]]; echo ${BASH_REMATCH[0]}; echo ${BASH_REMATCH[1]}

新增引號的問題與上一個例子中的問題相同,更多描述詳見 bash 的幫助文件。

需要注意這裡使用子組匹配時不需要使用反斜槓對左右括號進行轉義,sed 中是需要新增的。

=~ 表示以 pattern 對該操作符左邊的展開內容進行匹配,匹配到的結果將放到 BASH_REMATCH 陣列中,BASH_REMATCH[0] 表示匹配到的所有內容,BASH_REMATCH[1]–BASH_REMATCH[n] 依次存放匹配到的各個子組。這裡沒有說 n 的上限,也就不深究了吧。不過需要注意的是在 sed 中確實有明確的限制,一般為 12 吧,我需要查查資料!

需要注意這裡的 pattern ,可以直接使用其它變數,這樣程式設計變得更加靈活。

這是正則表示式的一個應用之一,藉助正則表示式我們可以高效的完成批量任務,既是重點也是難點!