Bash正则表达式 - 似乎无法匹配\ s,\ S等

时间:2013-08-29 14:44:39

标签: regex bash

我有一个试图从gparted获取信息块的脚本。

我的数据如下:

Disk /dev/sda: 42.9GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number  Start   End     Size    Type     File system     Flags
 1      1049kB  316MB   315MB   primary  ext4            boot
 2      316MB   38.7GB  38.4GB  primary  ext4
 3      38.7GB  42.9GB  4228MB  primary  linux-swap(v1)

log4net.xml
Model: VMware Virtual disk (scsi)
Disk /dev/sdb: 42.9GB
Sector size (logical/physical): 512B/512B
Partition Table: msdos

Number  Start   End     Size    Type     File system     Flags
 1      1049kB  316MB   315MB   primary  ext4            boot
 5      316MB   38.7GB  38.4GB  primary  ext4
 6      38.7GB  42.9GB  4228MB  primary  linux-swap(v1)

我使用正则表达式将其分成两个磁盘块

^ Disk(/ dev [\ S] +):((?!Disk)[\ s \ S])*

这适用于多线上。

当我在bash脚本中测试时,我似乎无法匹配\ s或\ S - 我做错了什么?

我正在通过以下脚本对此进行测试:

data=`cat disks.txt`
morematches=1
x=0
regex="^Disk (/dev[\S]+):((?!Disk)[\s\S])*"

if [[ $data =~ $regex ]]; then
echo "Matched"
while [ $morematches == 1 ]
do
        x=$[x+1]
        if [[ ${BASH_REMATCH[x]} != "" ]]; then
                echo $x "matched" ${BASH_REMATCH[x]}
        else
                echo $x "Did not match"
                morematches=0;
        fi

done

fi

但是,当我逐步测试正则表达式的部分时,每当我匹配\ s或\ S时,它都不起作用 - 我做错了什么?

5 个答案:

答案 0 :(得分:22)

可能不支持\ S和\ s,或者您不能将它们放在[ ]周围。请尝试使用此格式:

^Disk[[:space:]]+/dev[^[:space:]]+:[[:space:]]+[^[:space:]]+

修改

看起来你真的想要得到匹配的字段。我使脚本更简单,但我不确定它是否是你想要的输出:

#!/bin/bash 

regex='^Disk[[:space:]]+(/dev[^[:space:]]+):[[:space:]]+(.*)'

while read line; do
    [[ $line =~ $regex ]] && echo "${BASH_REMATCH[1]} matches ${BASH_REMATCH[2]}."
done < disks.txt

哪个产生

/dev/sda matches 42.9GB.
/dev/sdb matches 42.9GB.

答案 1 :(得分:3)

来自man bash

  

可以使用另外的二元运算符=〜   优先级为==和!=。使用时,右边的字符串   操作员是                 支持扩展正则表达式并相应匹配(如在regex(3)中)。

ERE不支持预测/后退。但是,您可以在代码中使用它们((?!Disk))。

这就是为什么你的正则表达式不会像你预期的那样匹配的原因。

答案 2 :(得分:3)

因为这是一个常见的常见问题解答,让我列出一些Bash不支持的构造,以及如何解决它们,其中有一个简单的解决方法。

常用的正则表达式有多种方言。 Bash支持的是扩展正则表达式的变体。这不同于例如许多在线正则表达式测试人员支持,这通常是更现代的Perl 5 / PCRE变体。

  • Bash不支持\d \D \s \S \w \W - 这些可以替换为等值的POSIX字符类{分别为{1}},[[:digit:]][^[:digit:]][[:space:]][^[:space:]][_[:alnum:]]。 (注意最后一种情况,其中[^_[:alnum:]] POSIX字符类使用下划线进行扩充,以完全等同于Perl [:alnum:]简写。)
  • Bash不支持非贪婪匹配。您有时可以用\w替换a.*?b以在实践中获得类似的效果,尽管两者并不完全相同。
  • Bash不支持a[^ab]*b(?<=before)等内容,实际上(?!after)的任何内容都是Perl扩展。这些问题没有简单的一般解决方法,但您可以经常将问题重新划分为可以避免外观的问题。

答案 3 :(得分:2)

我知道你已经“解决了”这个问题,但你原来的问题可能就像你在测试中引用$regex一样简单。即:

if [[ $data =~ "$regex" ]]; then

Bash变量扩展只会在字符串中填充,而原始正则表达式中的空格将会破坏测试,因为:

regex="^Disk (/dev[\S]+):((?!Disk)[\s\S])*"
if [[ $data =~ $regex ]]; then

相当于:

if [[ $data =~ ^Disk (/dev[\S]+):((?!Disk)[\s\S])* ]]; then

和bash / test将有一个有趣的时间来解释奖金参数和所有那些未加引号的元字符。

请记住,bash不会传递变量,会扩展它们。

答案 4 :(得分:0)

此外,[\s\S]相当于.,即任何字符。在我的shell上,[^\s]有效,但不是[\S]