BASH正则表达式匹配 - 包括括号中的括号中的括号以匹配?

时间:2012-04-16 21:15:40

标签: regex bash

我正在尝试做一个小小的bash脚本,它会清理我喜欢的一些电视节目下载剧集的文件和文件夹名称。它们通常看起来像“[www.Speed.Cd] - Some.Show.S07E14.720p.HDTV.X264-SOMEONE”,我基本上只想剥去那个speedcd广告位。

使用BASH中的正则表达式匹配很容易删除www.Speed.Cd,空格和破折号,但对于我的生活,我无法弄清楚如何将括号包含在要匹配的字符列表中。 [ - []不起作用,[ - \ [],[ - \\ [],[ - \\\ []或我要删除的括号前面的任意数量的转义字符都不起作用。

这是我到目前为止所得到的:

[[ "$newfile" =~ ^(.*)([- \[]*(www\.torrenting\.com|spastikustv|www\.speed\.cd|moviesp2p\.com)[- \]]*)(.*)$ ]] &&
    newfile="${BASH_REMATCH[1]}${BASH_REMATCH[4]}"

但它在括号上打破了。

有什么想法吗?

TIA, 丹尼尔:)

编辑:我应该注意到我正在使用“shopt -s nocasematch”来确保不区分大小写的匹配,以防万一你想知道:)

编辑2:感谢所有贡献者。我不是100%肯定哪个答案是“正确的”,因为我的陈述有几个问题。实际上,最准确的答案只是对jw013发布的问题的评论,但我当时没有得到它,因为我还没有理解空格应该被转义。我选择了aefxx,因为那个基本上都是这样说的,但是有解释:)我们也想在ormaaj的答案上加上正确的答案标记,因为他发现了我表达的更严重的问题。

无论如何,我上面使用的方法,尝试匹配和提取部分以保留和留下不需要的部分真的不是很优雅,并不会捕捉所有情况,甚至不是真正简单的像“一些。 Show.S07E14.720p.HDTV.X264-SOMEONE - [www.Speed.Cd]“。我改为重写它以匹配并提取不需要的部分,然后对原始字符串上的字符串进行字符串替换,就像这样(循环以防万一有多个品牌):

# Remove common torrent site brandings, including surrounding spaces, brackets, etc.:
while [[ "$newfile" =~ ([[\ {\(-]*(www\.)?(torrentday\.com|torrenting\.com|spastikustv|speed\.cd|moviesp2p\.com|publichd\.org|publichd|scenetime\.com|kingdom-release)[]\ }\)-]*) ]]; do
    newfile=${newfile//"${BASH_REMATCH[1]}"/}
done

4 个答案:

答案 0 :(得分:7)

好的,这是我第一次听说=~运算符,但这是我通过反复试验找到的结果:

if [[ $newfile =~ ^(.*)([-[:space:][]*(what|ever)[][:space:]-]*)(.*)$ ]] 
                          ^^^^^^^^^^              ^^^^^^^^^^

看起来很奇怪但实际上确实有效(只是测试了它)。

修改
引自Linux手册页正则表达式(7):

  

要在列表中包含文字],请将其设为第一个字符(遵循可能的^)。要包含文字 - ,使其成为范围的第一个或最后一个字符或第二个端点。要使用文字aq-aq作为范围的第一个端点,请将其括在“[。”中。和“。”“使其成为整理元素(见下文)。除了使用aq [aq(参见下一段)的这些和一些组合之外,所有其他特殊字符(包括aq \ aq)在括号表达式中失去其特殊意义。

答案 1 :(得分:4)

每当你正在使用正则表达式时,它在Bash版本之间最兼容,即使你设法避免将它们直接放在测试表达式中的所有陷阱,也要将正则表达式置于变量中。 http://mywiki.wooledge.org/BashPitfalls#if_.5B.5B_.24foo_.3D.2BAH4_.27some_RE.27_.5D.5D

您当前的正则表达式看起来像是在尝试选择匹配左括号前的任何内容。我猜你实际上是在试图通过以下方式保存例如3和4:

$ shopt -s nocasematch
$ newfile='[ www.Speed.Cd ] - Some.Show.S07E14.720p.HDTV.X264-SOMEONE'
$ re='^.*[-[:space:][]*(www\.torrenting\.com|spastikustv|www\.speed\.cd|moviesp2p\.com)[][:space:]-]*(.*)$'
$ [[ $newfile =~ $re ]]
$ declare -p BASH_REMATCH
declare -ar BASH_REMATCH='([0]="[ www.Speed.Cd ] - Some.Show.S07E14.720p.HDTV.X264-SOMEONE" [1]="www.Speed.Cd" [2]="Some.Show.S07E14.720p.HDTV.X264-SOMEONE")'

答案 2 :(得分:1)

基本问题很简单,如果不是很明显的话 BASH REGEX 完全不受保护(来自shell),并且不受双引号的保护。这意味着每个文字空间(和标签等)必须受到baskslash \ ...故事结束的保护。其余的只是让你的正则表达式满足你的需求。

另一件事;使用[\ [][]\ ]分别匹配[],范围为方括号构造(在本例中为空格)。

示例:

newfile="[ ]"
[[ "$newfile" =~ ^[\ []\ []\ ]$ ]] &&
    echo YES ||
    echo NO

答案 3 :(得分:0)

你可以尝试这样的事情(尽管你并不是100%清楚你要尝试过滤的情况:

newfile="[ www.Speed.Cd ] - Some.Show.S07E14.720p.HDTV.X264-SOMEONE"

if [[ $newfile =~ ^(.*)([^a-zA-Z0-9.]*\[.*\][^a-zA-Z0-9.]*)(.*)$ ]]; then 
    newfile="${BASH_REMATCH[1]}${BASH_REMATCH[3]}"
fi

echo $newfile
# Some.Show.S07E14.720p.HDTV.X264-SOMEONE

它只剥离[]之外的任何非alnum(和点)字符,以及[]

内的任何字符