我试图按照如下方式分离出路径的部分。我的输入路径采用以下可能的形式:
bucket
bucket/dir1
bucket/dir1/dir2
bucket/dir1/dir2/dir3
...
我想将路径的第一部分(bucket
)与字符串的其余部分(dir1/dir2/dir3/...
)分开,并将两者存储在单独的变量中。
下面给了我一些接近我想要的东西:
❯ BUCKET=$(echo "bucket/dir1/dir2" | sed 's@(^[^/]*)[/](.*)@1@')
❯ EXTENS=$(echo "bucket/dir1/dir2" | sed 's@(^[^/]*)[/](.*)@2@')
echo $BUCKET $EXTENS
❯ bucket dir1/dir2
然而,如果我只有bucket
作为输入(没有斜杠),它会失败:
❯ BUCKET=$(echo "bucket" | sed 's@(^[^/]*)[/](.*)@1@')
❯ EXTENS=$(echo "bucket" | sed 's@(^[^/]*)[/](.*)@2@')
echo $BUCKET $EXTENS
❯ bucket bucket
…因为,在没有第一个'/'的情况下,不会发生捕获,因此不会发生替换。当输入仅为'bucket'
时,我希望将$EXTENS
设置为空字符串""
。
谢谢!
对于如此简单的事情,您可以使用内置bash
而不是启动sed
:
$ path="bucket/dir1/dir2"
$ bucket="${path%%/*}"
$ extens="${path#$bucket}"
$ printf '|%s|%s|n' "$bucket" "$extens"
|bucket|/dir1/dir2|
$ path="bucket"
$ bucket="${path%%/*}"
$ extens="${path#$bucket}"
$ printf '|%s|%s|n' "$bucket" "$extens"
|bucket||
但是如果你真的想使用sed
和捕获组:
$ declare -a bucket_extens
$ mapfile -td '' bucket_extens < <(printf '%s' "bucket/dir1/dir2" | sed -E 's!([^/]*)(.*)!1x002!')
$ printf '|%s|%s|n' "${bucket_extens[@]}"
|bucket|/dir1/dir2|
$ mapfile -td '' bucket_extens < <(printf '%s' "bucket" | sed -E 's!([^/]*)(.*)!1x002!')
$ printf '|%s|%s|n' "${bucket_extens[@]}"
|bucket||
我们使用扩展正则表达式(-E
)来简化位,并使用!
作为替换命令的分隔符。第一个捕获组是不包含斜杠的任何内容,第二个捕获组是其他所有内容,如果没有其他内容,则不包含任何内容。
在替换字符串中,我们用NUL字符(x00
)分隔两个捕获组。然后使用mapfile
将结果赋值给bash数组bucket_extens
。
NUL技巧是一种处理文件名中包含空格,换行符…NUL是唯一不能成为文件名一部分的字符。mapfile
的-d ''
选项表示要映射的行以NUL分隔,而不是默认的换行符。
不要捕捉任何内容。相反,只需匹配您不想要的并将其替换为空:
BUCKET=$(echo "bucket" | sed 's@/.*@@'). # bucket
BUCKET=$(echo "bucket/dir1/dir2" | sed 's@/.*@@') # bucket
EXTENS=$(echo "bucket" | sed 's@[^/]*@@') # blank
EXTENS=$(echo "bucket/dir1/dir2" | sed 's@[^/]*@@') # /dir1/dir2
当你在正则表达式中放入斜杠时。没有斜杠的字符串不会匹配。让我们将斜杠设置为可选的/?
。(?
前的反斜杠由于sedBRE
,这是必需的。)那你可以试试:
#!/bin/bash
#path="bucket/dir1/dir2"
path="bucket"
bucket=$(echo "$path" | sed 's@(^[^/]*)/?(.*)@1@')
extens=$(echo "$path" | sed 's@(^[^/]*)/?(.*)@2@')
echo "$bucket" "$extens"
- 你不需要在斜杠前加上反斜杠
- 按照惯例,建议用户变量使用小写。