如果你使用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中,等等。索引0是完全匹配。
你应该意识到,如果没有锚,这个正则表达式(以及使用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操作符(变长向后查找)使前面的模式匹配,但不包括结果中的匹配。固定长度的等效值是(?<=)-模式将包含在右括号之前。如果量词可以匹配不同长度的字符串(例如+,*,{2,4}),则必须使用\K。
(?=)操作符匹配固定长度或可变长度模式,称为“超前查找”。它也不包括结果中匹配的字符串。
为了使匹配不区分大小写,使用(?i)操作符。它影响着后面的图案,所以它的位置很重要。
正则表达式可能需要根据文件名中是否有其他字符进行调整。您将注意到,在本例中,我展示了一个在捕获子字符串的同时连接字符串的示例。