如何通過分隔符拆分字元串導致未知數量的部分以及如何將結果收集到數組中?
我需要處理一些包含路徑的字元串。如何通過
/
分隔符拆分這樣的字元串,導致路徑部分的數量未知,最後我如何提取生成的路徑部分?
cut
顯然不是首選工具,因為它需要您事先知道零件的數量,並且它也不會輸出每個零件以便我可以使用readarray
或mapfile
將它們收集到數組中。
在 Bash 中,您可以使用
read -a
和 here-string 將字元串拆分為數組:path=/foo/bar/doo IFS=/ read -r -a parts <<< "$path"
foo
這將給出一個包含四個元素(空)、 、bar
和的數組doo
。這不適用於包含換行符的路徑,因為
read
預設情況下將換行符視為分隔符。為防止這種情況,您需要添加-d ''
,但問題是 here-string 添加了一個換行符,然後必須從最後一個元素中刪除該換行符:path=$'/path/with/new\nlines' IFS=/ read -d '' -r -a parts <<< "$path" parts[-1]=${parts[-1]%$'\n'}
(
parts[-1]
引用數組的最後一個元素,並${var%text}
擴展為刪除var
尾部匹配的值。)text
另請注意,如果路徑可以包含重複的斜杠,例如
foo//bar
,您將在中間得到空數組元素。同樣,如果路徑以斜杠結尾,您將在末尾得到一個空元素。您可以忽略它們,或者使用類似這樣的方法預處理刪除它們的路徑,以刪除重複的斜杠
shopt -s extglob path="${path//+('/')/'/'}"
並刪除尾部斜杠:
shopt -s extglob path="${path%+('/')}"
但話又說回來,請注意,在路徑名的開頭,雙斜杠
//foo
是保留的特殊符號,與單(或三重等)斜杠不同,但您在實踐中不太可能看到,所以我會忽略它。
在
bash
, 對於單字元分隔符,您可以在禁用 glob 部分後使用 split+glob 運算符(在列表上下文中不加引號的擴展):string='foo/bar baz/asd..' IFS=/ set -o noglob array=( $string )
請注意,它拆分
string='/foo/'
為""
and"foo"
only(與拆分時相同string='/foo'
。要拆分為""
,"foo"
and""
,您可以執行以下操作:IFS=/ set -o noglob array=( $string'' )
儘管然後拆分
string=''
為一個空元素而不是零元素。在(除非在/仿真中,在不帶
zsh
引號的擴展時不會執行 split+glob ),您可以使用不限於單字元分隔符的參數擴展標誌:sh``ksh``s
array=( ${(s[/])string} )
刪除空元素,或者:
array=( "${(@s[/])string}" )
保留空元素。
/foo/
然後被分割成""
,"foo"
和""
空字元串成零元素。您可以拆分儲存在變數中的分隔符:
array=( "${(@ps[$delimiter])string}" )
該
p
標誌還允許您輸入轉義序列,例如\0
,\n
,儘管這兩個具有快捷標誌:f
在換行符0
上拆分,在 NUL 上拆分(用於拆分find -print0
,grep -lZ
,sort -z
… 的輸出,例如files=( ${(0)"$(grep -lZ pattern -- *)"} )
)。在
zsh
中,您還可以將數組變數綁定到標量變數,並以給定的單字節作為分隔符。$path
inzsh
實際上是一個特殊的數組,它以這種方式$PATH
與:
作為分隔符相關聯(靈感來自csh
)。您可以對任何變數執行此操作,例如:typeset -T string array /
將
/
-separated綁定$string
到$array
數組。