Bash

Bash 正則表達式和 IFS 拆分

  • February 27, 2019

我有以下問題:我想從字元串中提取括號內的文本(帶或不帶括號)。我的字元串如下所示:

STR="[1] [2][345] [678 9] foo bar"

我最初想使用 bash 正則表達式和 BASH_REMATCH。我最終使用了以下程式碼:

regex='\[([^\]]*)\](.*)'
MATCHES=()
STR="[1] [2][345] [678 9] foo bar"
while [[ -n $STR && $STR =~ $regex ]];
do
   MATCHES+=("${BASH_REMATCH[1]}")
   STR=${BASH_REMATCH[2]}
   echo -e "matches: ${BASH_REMATCH[1]} -> ${BASH_REMATCH[2]}"
done

這種工作但我的問題是它只會在括號內擷取一個字元,因此[345]會導致3.

我不知道為什麼會這樣,所以我最終還是使用了 grep 和 PCRE。我目前的解決方案是

regex="\[[^\]]*?\]"
if [[ $(grep -o '\[.*\]' <<< $STR) ]];
then
   MATCHES=$(grep -oP "$regex" <<< $STR)
else
   echo "No special flags provided."
   exit 0
fi

然後我進行一個 for 循環:

for arg in $MATCHES;
do
   echo $arg
done

問題是它沒有像我希望的那樣分隔欄位。我使用 hexdump 來找出正確的分隔符:

hexdump -C <<< $MATCHES

令我驚訝的是,這表明分隔符是十六進制0a的,即LF。這不是問題,因為我知道 for 循環使用 IFS 進行拆分。然後我通過使用將 IFS 設置為 LF IFS=$'\n'。令我(再次)驚訝的是,0a0a再次根據 hexdump 將 IFS 的值設置為 。所以那沒有用。然後我將 IFS 的值設置為,IFS=''並且(對於我的第三個驚喜)將值設置為0a. 但這也不起作用, for 循環沒有改變行為。也許我的腳本沒有正確設置 IFS 的範圍?

我的問題如下:

  1. 為什麼原來的 bash only 正則表達式方法不起作用?為什麼它只擷取一個字元?regex101 dot com 顯示了預期的行為,但話又說回來,它不提供 bash 正則表達式模式。

  2. 為什麼 IFS 設置不能像我預期的那樣工作?它添加了一個“額外的”LF,即使我將它設置為空。

3)為什麼 IFS 似乎不影響 for 循環?

4)我是否有更簡單的方法來解決原始問題([foo] [bar] [foo bar]從字元串[foo] [bar] 1 asdf[foo bar]中提取,我可以為每個括號對循環)。


獎金問題!

B) 我對何時應該將變數或表達式括在引號或雙引號中感到困惑。我已經閱讀了一些關於 globbing 和參數擴展的內容,現在我正在尋找更深入的內容。有什麼建議嗎?

要匹配任何不包含 a 的非空字元串],請使用[^]]+.

Using[^\]]*將匹配一個非\後跟零個或多個]. 這就是為什麼您設法解析出 the1和 the2而不是其他字元串的原因。

IFS變數不會在您的第一段程式碼中發揮作用。裡面的變數[[ ... ]]不需要雙引號。

要列印數組的單獨元素,請使用

printf '%s\n' "${MATCHES[@]}"

或者

for elem in "${MATCHES[@]}"; do
   printf '%s\n' "$elem"
done

只是$MATCHES將擴展為僅數組的第一個元素(並將對值應用分詞和文件名萬用字元)。

引用自:https://unix.stackexchange.com/questions/503308