如果您使用的是Bash,则甚至不必使用grep
:
files="*.jpg"
regex="[0-9]+_([a-z]+)_[0-9a-z]*"
for f in $files # unquoted in order to allow the glob to expand
do
if [[ $f =~ $regex ]]
then
name="${BASH_REMATCH[1]}"
echo "${name}.jpg" # concatenate strings
name="${name}.jpg" # same thing stored in a variable
else
echo "$f doesn't match" >&2 # this could get noisy if there are a lot of non-matching files
fi
done
最好将正则表达式放在变量中。如果按字面意义包含某些模式,将无法使用。
这使用的 =~
是Bash的正则表达式匹配运算符。匹配结果将保存到名为的数组中$BASH_REMATCH
。第一个捕获组存储在索引1中,第二个(如果有)存储在索引2中,依此类推。索引零是完全匹配项。
您应该意识到,没有锚,此正则表达式(以及使用的正则表达式grep
)将匹配以下任何示例以及更多示例,而这些可能并不是您想要的:
123_abc_d4e5
xyz123_abc_d4e5
123_abc_d4e5.xyz
xyz123_abc_d4e5.xyz
为了消除第二个和第四个示例,使正则表达式如下所示:
^[0-9]+_([a-z]+)_[0-9a-z]*
表示字符串必须以一个或多个数字开头。克拉代表弦的开头。如果在正则表达式的末尾添加美元符号,如下所示:
^[0-9]+_([a-z]+)_[0-9a-z]*$
那么第三个示例也将被删除,因为该点不在正则表达式中,并且美元符号表示字符串的结尾。请注意,第四个示例也未能通过此匹配。
如果您使用的是GNU grep
(大约2.5或更高版本,我想\K
是在添加运算符时):
name=$(echo "$f" | grep -Po '(?i)[0-9]+_\K[a-z]+(?=_[0-9a-z]*)').jpg
的\K
操作者(可变长度向后看)导致前述图案匹配,但不包括在结果中的匹配。固定长度等效项是(?<=)
-模式将包含在右括号之前。\K
如果量词可以匹配不同长度的字符串(例如,,)+
,则必须使用。*
{2,4}
所述(?=)
操作者匹配固定的或可变长度的模式和被称为“先行”。它也不在结果中包含匹配的字符串。
为了使匹配不区分大小写,使用了(?i)
运算符。它会影响其后的模式,因此其位置很重要。
根据文件名中是否还有其他字符,可能需要调整正则表达式。您会注意到,在这种情况下,我展示了一个在捕获子字符串的同时串联一个字符串的示例。