我需要处理一些包含路径的字符串。如何用/
分隔符分割这样的字符串,导致未知数量的路径部分,以及最终如何提取生成的路径部分?
cut
显然不是选择的工具,因为它需要您事先知道零件的数量,而且它也不会输出每个零件以便我可以使用它们readarray
或mapfile
将它们收集到数组中。
答案1
在 中bash
,对于单字符分隔符,您可以在禁用 glob 部分后使用 split+glob 运算符(在列表上下文中保留未加引号的扩展):
string='foo/bar
baz/asd..'
IFS=/
set -o noglob
array=( $string )
请注意,它仅拆分string='/foo/'
为""
和"foo"
(与拆分 时相同string='/foo'
。要拆分为""
,"foo"
和""
,您可以执行以下操作:
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
按换行符分割,按 NUL 分割(可用于分割, , ...0
的输出,例如)。find -print0
grep -lZ
sort -z
files=( ${(0)"$(grep -lZ pattern -- *)"} )
在 中zsh
,您还可以领带将数组变量转换为标量变量,并以给定的单字节作为分隔符。$path
inzsh
实际上是一个特殊的数组,它以这种方式与作为分隔符联系在一起$PATH
(:
灵感来自csh
)。您可以对任何变量执行此操作,例如:
typeset -T string array /
将/
-separate$string
与$array
数组相连。
答案2
在 Bash 中,您可以使用read -a
here-string 将字符串拆分为数组:
path=/foo/bar/doo
IFS=/ read -r -a parts <<< "$path"
这将给出一个包含四个元素(空)、foo
、bar
和 的数组doo
。
这不适用于包含换行符的路径,因为read
默认情况下将换行符视为分隔符。为了防止这种情况,您需要添加-d ''
,但是存在一个问题,即此处字符串添加换行符,然后必须从最后一个元素中删除换行符:
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
是保留的特殊符号,与单斜杠(或三斜杠等)斜杠不同,但您在实践中不太可能看到这一点,所以我将忽略它。
答案3
...不输出每个部分以便我可以使用
readarray
或mapfile
使用mapfile/readarray,提供完整的字符串并设置分隔符。例如,
str='/f
oo/bar/'
mapfile -d / arr < <(printf '%s' "$str")
declare -p arr
输出:
declare -a arr=([0]="/" [1]=$'f\noo/' [2]="bar/")