如何用分隔符分割字符串,导致未知数量的部分以及如何将结果收集到数组中?

如何用分隔符分割字符串,导致未知数量的部分以及如何将结果收集到数组中?

我需要处理一些包含路径的字符串。如何用/分隔符分割这样的字符串,导致未知数量的路径部分,以及最终如何提取生成的路径部分?

cut显然不是选择的工具,因为它需要您事先知道零件的数量,而且它也不会输出每个零件以便我可以使用它们readarraymapfile将它们收集到数组中。

答案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 ),您可以使用参数扩展标志,该标志不限于单字符分隔符:shkshs

array=( ${(s[/])string} )

它删除空元素,或者:

array=( "${(@s[/])string}" )

保留空元素。/foo/然后将其拆分为"","foo"""并将空字符串拆分为零元素。

您可以使用存储在变量中的分隔符进行拆分:

array=( "${(@ps[$delimiter])string}" )

p标志还允许您输入转义序列,例如\0, \n,尽管这两个具有快捷方式标志:f按换行符分割,按 NUL 分割(可用于分割, , ...0的输出,例如)。find -print0grep -lZsort -zfiles=( ${(0)"$(grep -lZ pattern -- *)"} )

在 中zsh,您还可以领带将数组变量转换为标量变量,并以给定的单字节作为分隔符。$pathinzsh实际上是一个特殊的数组,它以这种方式与作为分隔符联系在一起$PATH:灵感来自csh)。您可以对任何变量执行此操作,例如:

typeset -T string array /

/-separate$string$array数组相连。

答案2

在 Bash 中,您可以使用read -ahere-string 将字符串拆分为数组:

path=/foo/bar/doo
IFS=/ read -r -a parts <<< "$path"

这将给出一个包含四个元素(空)、foobar和 的数组doo

这不适用于包含换行符的路径,因为read默认情况下将换行符视为分隔符。为了防止这种情况,您需要添加-d '',但是存在一个问题,即此处字符串添加换行符,然后必须从最后一个元素中删除换行符:

path=$'/path/with/new\nlines'
IFS=/ read -d '' -r -a parts <<< "$path"
parts[-1]=${parts[-1]%$'\n'}

parts[-1]指数组的最后一个元素,并扩展到删除尾部匹配${var%text}的值。)vartext

另请注意,如果路径可以包含重复的斜杠,例如foo//bar,您将在中间得到空数组元素。同样,如果路径以斜杠结尾,您将在末尾得到一个空元素。

您可以忽略它们,或者预处理路径以删除它们,使用类似的方法来删除重复的斜杠

shopt -s extglob
path="${path//+('/')/'/'}"

并删除尾部斜杠:

shopt -s extglob
path="${path%+('/')}"

但话又说回来,请注意,在路径名的开头,双斜杠//foo是保留的特殊符号,与单斜杠(或三斜杠等)斜杠不同,但您在实践中不太可能看到这一点,所以我将忽略它。

答案3

...不输出每个部分以便我可以使用readarraymapfile

使用mapfile/readarray,提供完整的字符串并设置分隔符。例如,

str='/f
oo/bar/'

mapfile -d / arr < <(printf '%s' "$str")

declare -p arr

输出:

declare -a arr=([0]="/" [1]=$'f\noo/' [2]="bar/")

相关内容