使用 bash 从方括号中提取数字

使用 bash 从方括号中提取数字

我的文件如下所示:

[581]((((((((501:0.00024264,451:0.00024264):0.000316197,310:0.000558837):0.00857295,((589:0.000409158,538:0.000409158):0.000658084,207:0.00106724
):0.00806454):0.0429702,(((198:0.00390205,91:0.00390205):0.016191,79:0.0200931):0.0147515,(187:0.00133008,50:0.00133008):0.0335145):0.0172574):0.
127506,((140:0.00253019,117:0.00253019):0.0533693,(((533:0.00728707,(463:8.80494e-05,450:8.80494e-05):0.00719902):0.0217722,389:0.0290593):0.0253
931,(((141:0.018004,107:0.018004):0.0143861,(111:0.00396127,(106:0.00161229,12:0.00161229):0.00234898):0.0284289):0.0145736,(129:0.0195982,((123:
0.0105973,66:0.0105973):0.0084867,10:0.019084):0.000514243):0.0273656):0.00748854):0.00144709):0.123708):0.000944439,((181:0.00108761,71:0.00108761):0.0819772);  
[50]((((((((501:0.00024264,451:0.00024264):0.000316197,310:0.000558837):0.00857295,((589:0.000409158,538:0.000409158):0.000658084,207:0.00106724):0.00806454):0.0429702,(((198:0.00390205,91:0.00390205):0.016191,79:0.0200931):0.0147515,(187:0.00133008,50:0.00133008):0.0335145):0.0172574):0.127506,((140:0.00253019,117:0.00253019):0.0533693,(((533:0.00728707,(463:8.80494e-05,450:8.80494e-05):0.00719902):0.0217722,389:0.0290593):0.0253931,(((141:0.018004,107:0.018004):0.0143861,(111:0.00396127,(106:0.00161229,12:0.00161229):0.00234898):0.0284289):0.0145736,(129:0.0195982,((123:0.0105973,66:0.0105973):0.0084867,10:0.019084):0.000514243):0.0273656):0.00748854):0.00144709):0.123708):0.000944439,((181:0.00108761,71:0.00108761):0.0819772);

每一行都以模式开头[number]。每一行都以模式结尾);

我需要把每行开头的方括号里的数字取出来,写入一个新文件,之前我不知道这个文件有多少行。

答案1

您只需一个grep命令。这是因为 GNU grep 允许您使用Perl 正则表达式-P),支持零宽度环视断言\K并且(?= ),在这种情况下):

grep -oP '^\[\K\d+(?=\])' infile

如上所述,这会将输出发送到您的终端。要将其重定向到文件,请使用:

grep -oP '^\[\K\d+(?=\])' infile > outfile

该方法的优点是简洁明了。它匹配的文本

  • 前面有 ( \K)

    • 字符[\[) --\是必需的,[否则在正则表达式中具有特殊含义
    • 出现在行首的 ( ^);
  • +由一个或多个( )数字组成( \d);

  • 后面跟着 ( (?= ))

    • 字符]( \]) – 与 类似[\强制]进行字面匹配。

答案2

使用sed

  • < inputfile sed -n 's/^\[\([0-9]*\)\].*$/\1/p' > out

指令分解

  • < inputfile:将内容重定向inputfilestdin
  • -n:抑制输出
  • > out:将内容重定向stdoutout

正则表达式细分

  • s:执行替换
  • /: 启动正则表达式
  • ^: 匹配行首
  • \[: 匹配一个[字符
  • \(:开始捕获组
  • [0-9]*:匹配任意数量的数字
  • \):停止捕获组
  • \]: 匹配一个]字符
  • .*: 匹配任意数量的任意字符
  • $: 匹配行尾
  • /:停止正则表达式/开始替换
  • \1: 替换为第一个捕获组
  • /:停止替换
  • p:仅打印匹配的行

使用grep+ (如果您需要一种可以在 Ubuntu 和不支持 PCREtr的其他操作系统上运行的方法- 否则,请参阅grepEliah Kagan 的grep唯一版本):

  • < inputfile grep -o '^\[[0-9]*\]' | tr -d '[]' > out

指令分解

  • < inputfilein grep:将内容重定向inputfilestdin
  • -oin grep:仅打印匹配项
  • -din tr:删除字符
  • > outin tr:将内容重定向stdoutout

正则表达式细分

  • ^: 匹配行首
  • \[: 匹配一个[字符
  • [0-9]*:匹配任意数量的数字
  • \]: 匹配一个]字符

答案3

道路perl

perl -ne 'print "$1\n" if /^\[([0-9]*)\].*/' testdata > out

或者awk

awk 'match($0, /^\[[0-9]*\]/) {print substr($0, RSTART + 1, RLENGTH - 2)}' testdata > out

在两种情况下都使用了正则表达式:

^\[[0-9]*\]

解释

  • /^\[[0-9]*\]/

    • ^断言字符串开头的位置

    • \[与字符[逐字匹配

    • [0-9]*匹配下面列表中的单个字符

      • 量词:*零次至无限次之间,尽可能多次,根据需要返回 [贪婪]

      • 0-90 到 9 之间的单个字符

    • \]与字符]逐字匹配

    正则表达式可视化
    (来源:debuggex.com

    Debuggex 演示

答案4

python使用re模块的解决方案并考虑两种情况:

#!/usr/bin/env python2
import re
with open('/path/to/file.txt') as f:
    for line in f:
        digits_case_1 = re.search(r'(?<=^\[)\d+(?=\])', line)
        digits_case_2 = re.search(r'(?<=^\[)\d+(?=\].*\);$)', line)
        if digits_case_1:
            print 'Not considering ");" at end: ' + digits_case_1.group()
        if digits_case_2:
            print 'Considering ");" at end: ' + digits_case_2.group()

输出 :

Not considering ");" at end: 581
Not considering ");" at end: 50
Considering ");" at end: 50

这里我考虑了两种情况,因为您的问题对我来说似乎不清楚。

  • digits_case_1将在行首打印匹配的数字[],它不会考虑该行是否以 结尾);

  • digits_case_2[]仅当行以 结尾时才会在行首打印之间的数字);

相关内容