【问题标题】:Regex "^[[:digit:]]$" not working as expected in AWK/GAWK正则表达式 "^[[:digit:]]$" 在 AWK/GAWK 中无法按预期工作
【发布时间】:2024-01-01 02:52:01
【问题描述】:

我在 RHEL 上的 GAWK 版本是:

gawk-3.1.5-15.el5

我想打印一行,如果它的第一个字段包含所有数字(没有特殊字符,甚至要考虑空格)

Example:

echo "123456789012345,3" | awk -F, '{if ($1 ~ /^[[:digit:]]$/)  print $0}'

Output:
Nothing

Expected Output:
123456789012345,3

这里出了什么问题?我的 AWK 版本不理解 GNU 字符类吗?请帮忙

【问题讨论】:

    标签: awk gnu gawk character-class


    【解决方案1】:

    要匹配[[:digit:]] 字符类中的多个数字,请添加+,这意味着匹配$1 中的一个或多个数字。

    echo "123456789012345,3" | awk -F, '{if ($1 ~ /^([[:digit:]]+)$/)  print $0}'
    123456789012345,3
    

    满足您的要求。

    一种更惯用的方法(如 cmets 建议的那样)是删除 print 并在行上直接匹配并打印它,

    echo "123456789012345,3" | awk -F, '$1 ~ /^([[:digit:]]+)$/'
    123456789012345,3
    

    更多的例子证明了这一点,

    echo "a1,3" | awk -F, '$1 ~ /^([[:digit:]]+)$/'
    

    (和)

    echo "aa,3" | awk -F, '$1 ~ /^([[:digit:]]+)$/'
    

    根据要求产生任何输出。

    另一种符合POSIX 的方法可以对数字进行严格的长度检查,如下所示,其中{3} 表示匹配长度。

    echo "123,3" |  awk --posix -F, '$1 ~ /^[0-9]{3}$/'
    123,3
    

    (和)

    echo "12,3" |  awk --posix -F, '$1 ~ /^[0-9]{3}$/'
    

    不产生任何输出。

    如果您使用的是相对较新版本的bash shell,它支持原生regEx 运算符和~ 使用上述POSIX 字符类,类似于

    #!/bin/bash
    
    while IFS=',' read -r row1 row2
    do
       [[ $row1 =~ ^([[:digit:]]+)$ ]] && printf "%s,%s\n" "$row1" "$row2"
    done < file
    

    对于输入文件说file

    $ cat file
    122,12
    a1,22
    aa,12
    

    脚本产生,

    $ bash script.sh
    122,12
    

    虽然这可行,但bash regEx 可能会更慢,使用字符串操作的相对直接的方式类似于

    while IFS=',' read -r row1 row2
    do
       [[ -z "${row1//[0-9]/}" ]] && printf "%s,%s\n" "$row1" "$row2"
    done < file
    

    "${row1//[0-9]/}" 从行中删除所有数字,并且仅当变量中没有其他字符时条件才成立。

    【讨论】:

    • 出于某种原因,专家们鼓励使用更多惯用的awk,如echo "123456789012345,3" | awk -F, '$1 ~ /^[[:digit:]]*$/'print 这里不是多余的吗?
    • @sjsam:当然可以!有时,当使用 OP 自己的命令并在其之上进行修改时,一些微小的细节会丢失。不错的收获!随意编辑它,这是您的有效观点!
    • 我可能不会,因为您已经介绍了 op 的正则表达式匹配有什么问题。顺便说一句,如果操作有一个像echo ",3" | awk -F, '$1 ~ /^[[:digit:]]*$/' 这样的输入会更有趣
    • 由于 OP 使用的是 3.1.5 版的 Gnu awk,您可能应该将 --posix 开关添加到量词 ({n,m}) 示例中。
    • @All:谢谢各位。我找到了我所缺少的。来自@Ravinder 的echo "123456789012345,3" | awk -F, '{if ($1 ~ /^([[:digit:]]*)$/) print $0}' 或来自@Inian 的echo "123456789012345,3" | awk -F, '{if ($1 ~ /^([[:digit:]]+)$/) print $0}' 可以解决问题。
    【解决方案2】:

    在这里,您正在打印与模式匹配的每一行。这正是grep 的目的。由于@Inian 出色地告诉您代码有什么问题,让我提出一个替代的基于grep 的答案,它与awk 命令完全相同(尽管速度更快):

    grep -E '^[[:digit:]]+,'
    

    【讨论】:

    • @ xhienne :我需要处理的实际文件会非常大。这就是使用 awk 的原因。我刚刚从我原本完整的脚本中取出了一个代码行,以避免不必要的混淆,并且非常清楚我缺少什么以及我期望什么。
    • @dig_123 如果您的文件非常大,这就是选择grep 而不是awk 的原因,这可能会慢100 倍以上。除非您需要awk 中的高级功能?也许你可以把你的awk 放在grep 的输出上,我猜你会看到一些真正的加速。
    【解决方案3】:

    您能否尝试关注并告诉我这是否有帮助。

    echo "123456789012345,3" | awk -F, '{if ($1 ~ /^([[:digit:]]*)$/)  print $0}'
    

    编辑:上面的代码也可以简化为如下。

    echo "123456789012345,3" | awk -F, '($1 ~ /^[[:digit:]]*$/)'
    

    【讨论】:

      最近更新 更多