Bash:通过模式进行过滤和替换



给定由空格分隔的路径字符串:

path/folderA/fileA1 path/folderA/subFolderA/fileA2 path/folderB/fileB1
  1. 我想要一个由空格分隔的路径字符串,只有以path/folderA/开头的路径
    输出:path/folderA/fileA1 path/folderA/subFolderA/fileA2

  2. 然后从该字符串中删除路径/folderA/的任何匹配项
    最终输出:fileA1 subFolderA/fileA2

这能用一行完成吗?

如果你从一个字符串开始,那么嵌入的空格、换行符或其他有问题的字符可能会出错。这就是为什么使用globs或null终止值通常更好的原因。

也就是说,您可以使用各种内置和扩展来从给定的示例中获得您想要的结果。请注意,必须正确转义正斜杠或将其存储在带引号的字符串中,以避免干扰扩展语法。例如:

path_str="path/folderA/fileA1 path/folderA/subFolderA/fileA2 path/folderB/fileB1"
match_str="path/folderA/"
read -ra paths <<< "$path_str"
for i in "${!paths[@]}"; do
[[ ! "${paths[i]}" =~ $match_str ]] && unset paths[i]
done
echo "${paths[@]//$match_str}"

这将打印:

fileA1 subFolderA/fileA2

使用grep

echo " $str" | grep -oP '(?<=spath/folderA/)S+' | xargs

-P允许使用Perl正则表达式语法,您可以使用(?<=pattern),这是一个积极的前瞻性断言。此外,-o只保留该模式之后的匹配部分,即S+,一系列非空白字符(直到我们找到下一个空格、制表符、换行符等(

此外,grep输出总是用换行符分隔,因此您必须通过管道连接到tr 'n' ' 'xargs或类似的文件才能得到一行。

编辑:为了只匹配路径的开头,我添加了s(一个空白字符(,并将输入作为" $str"提供。这似乎更容易解决,因为b也匹配/,而(^|s)抛出grep: lookbehind assertion is not fixed length。所以用这个测试是可以的:

> echo "$str"
path/folderA/fileA1 path/folderA/subfolderA/fileA2 path/path/folderA/not
> echo " $str" | grep -owP '(?<=spath/folderA/)S+' | xargs
fileA1 subFolderA/fileA2

您可以简单地使用awk来匹配每个字段中的最后一组单词字符并输出它们,例如

awk '{for (i=1; i<=NF; i++) if ($i ~ /folderA/) { match($i,/w+$/); print substr($i,RSTART,RLENGTH)}}' <<< $path_str

示例使用/输出

path_str="path/folderA/fileA1 path/folderA/subFolderA/fileA2 path/folderB/fileB1"
awk '{for (i=1; i<=NF; i++) if ($i ~ /folderA/) { match($i,/w+$/); print substr($i,RSTART,RLENGTH)}}' <<< $path_str
fileA1
fileA2

您可以根据需要调整输出格式。如果您希望输出全部在一行上,或者如果您希望使用命令替换在新数组中捕获输出,则由您决定。

使用Bash参数展开

如果您想使用参数扩展子串删除,您可以使用一个简单的循环和扩展$(var##*/}从每个路径组件中删除所有内容,直到最后的'/',例如

path_str="path/folderA/fileA1 path/folderA/subFolderA/fileA2 path/folderB/fileB1"
for i in $path_str; do 
[[ $i =~ folderA ]] && echo ${i##*/}
done
fileA1
fileA2

对于您的情况,参数扩展可能是最有效的,因为它是shell的内置功能,可以避免生成子shell。然而,如果您有几十万个组件,那么我可能会让awk来处理它。

带有子字符串删除的符合POSIX的参数扩展集为:

${var#pattern}      Strip shortest match of pattern from front of $var
${var##pattern}     Strip longest match of pattern from front of $var
${var%pattern}      Strip shortest match of pattern from back of $var
${var%%pattern}     Strip longest match of pattern from back of $var

除了POSIX提供的参数扩展之外,Bash还提供了更多的参数扩展。包括从子字符串替换到字符大小写转换的所有内容。

如果您还有其他问题,请告诉我。

最新更新