18

我有一个脚本试图从 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

但是,当我遍历正则表达式的测试部分时,每当我匹配 a \sor\S时,它都不起作用——我做错了什么?

4

5 回答 5

26

也许 \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.
于 2013-08-29T14:49:59.447 回答
13

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

常用的正则表达式有多种方言。Bash 支持的是扩展正则表达式的一种变体。这与许多在线正则表达式测试器所支持的不同,后者通常是更现代的 Perl 5 / PCRE 变体。

  • Bash 不支持\d \D \s \S \w \W- 这些可以分别替换为 POSIX 字符类等效项[[:digit:]][^[:digit:]][[:space:]][^[:space:]][_[:alnum:]][^_[:alnum:]]。(请注意最后一种情况,其中[:alnum:]POSIX 字符类使用下划线进行扩充,以完全等同于 Perl\w速记。)
  • Bash 不支持非贪婪匹配。您有时可以a.*?b用类似的东西替换以a[^ab]*b在实践中获得类似的效果,尽管两者并不完全相同。
  • Bash 不支持非捕获括号(?:...)。在简单的情况下,只需使用捕获括号即可(...);当然,如果您使用捕获组和/或反向引用,这将重新编号您的捕获组。
  • Bash 不支持类似(?<=before)or的外观(?!after),实际上任何带有(?Perl 扩展的东西。这些没有简单的通用解决方法,尽管您通常可以将问题重新表述为可以避免环顾的问题。
于 2018-02-21T05:44:21.440 回答
3

man bash

额外的二元运算符 =~ 可用,其优先级与 == 和 != 相同。使用它时,运算符右侧的字符串被视为 扩展的正则表达式并进行相应匹配(如 regex(3) 中所示)。

ERE 不支持前瞻/后视。但是,您的代码中有它们 ( (?!Disk))。

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

于 2013-08-29T14:53:52.943 回答
0

此外,[\s\S]等价于.,即任何字符。在我的外壳上,[^\s]工作但不是[\S].

于 2013-08-29T15:02:18.687 回答
0

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

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 不会传递变量,它会扩展它们。

于 2013-08-29T19:38:59.990 回答