【问题标题】:Regular expressions and Shell scripts正则表达式和 Shell 脚本
【发布时间】:2015-09-16 13:28:27
【问题描述】:

我学习了正则表达式和 shell 脚本。我有一个目录 /work/test/ ,其中有多个文件,例如以下文件:needstc_30554-r-00051, profilemd5_30323-r-00053, modified_30394-r-00053。

我只想从以未更改开头的文件中提取第一个数字,例如未更改的_30397-r-30554 文件,这种情况下的数字是 30397。

我一直在玩正则表达式,并且能够使用以下内容从一个文件中提取 id:

    str='profiles_060315091024_30398-r-00006.avro'
    myvar=$(awk -F'[_-]' '{print $3}' <<< "$str")

所以我的问题是:

我怎样才能进入该目录并仅从以未更改开头的文件中获取第一个数字?

谢谢

【问题讨论】:

    标签: regex shell


    【解决方案1】:

    我会使用 ls 输出中的 GrepAWK (通过管道)。

    ls | grep '^unchanged_' | awk -F'[_-]' '{print $2}'
    
    1. ls:获取目录的文件名
    2. grep:仅获取匹配的文件(文件名过滤)
    3. awk:基本上这与您的原始样本相同(注意:数字应为$2

    【讨论】:

    • 如何在 ls 目录中指定??
    • 最后一个问题。名称不变之前的^是什么目的
    • 在正则表达式中^ 表示字符串的起点。它匹配 'unchanged_...' 但不匹配 '(any character+)unchanged_...'。如果您确定您的文件的名称中除了字符串的起始位置之外没有包含“未更改”一词,则不需要。
    【解决方案2】:

    您可以使用 find 命令获取文件名列表,然后使用 cut 命令提取您想要的部分。然后可以使用 for 循环对它们进行迭代,但这要求所有结果都适合单个 shell 命令行,并且如果目录中的文件过多,则命令将失败。 while 循环将处理任意数量的文件。

    find /work/test -type f -name 'unchanged*' | \
        cut -d_ -f2 | cut -d- -f1 | \
        while read fname;do echo $fname;done
    

    如果您只需要值列表,则可以省略 while 循环 - 它只是作为占位符,以防您想对每个值执行某些操作。

    find命令后的第一个参数是顶层目录; find 将递归到任何子目录。 “-type f”将其输出限制为常规文件。 -name 选项将其输出限制为仅以未更改开头的文件。

    "cut" 是一个很好的实用程序,用于提取分隔符之间的字段。第一个剪切的“-d_”表示使用下划线作为分隔符,“-f2”表示抓取第二个字段;这给了我们下划线之后的一切。接下来,我们指定一个破折号作为分隔符并获取第一个破折号之前的内容;这是我们的号码。我们得到一个流,每行一个,我们将其传递到 while 循环中。 read 命令将一次将一个以空格分隔的单词读入给定的变量名中,并让您随心所欲地使用它。

    上述命令不能很好地处理包含换行符的异常文件名,或包含空格的提取术语,但听起来你在这里不需要处理。

    【讨论】:

    • 感谢您的解释。这是一个很好的解决方案。我喜欢这样一个事实,即如果我不需要它,我不需要使用 for 循环或 while 循环。其他答案也很有帮助,但这个可以满足我的需要。
    【解决方案3】:

    步骤 1) 使用通配符选择匹配文件:unchanged_*

    步骤 2) 提取数字。您可以使用正则表达式,但使用纯 shell 构造更简单的方法是删除数字前后的内容。

    这是什么样子的:

    cd /work/test/
    
    for file in unchanged_*; do
        number=${file#unchanged_}   # remove "unchanged_"
        number=${number%%-*}        # remove everything after dash
    
        echo "$number"
    done
    

    【讨论】:

    • 分而治之。我喜欢它。
    【解决方案4】:

    我建议perl:

    #!/usr/bin/env perl
    
    use strict;
    use warnings;
    
    #iterate files in current directory matching file spec
    for ( glob("./unchanged_*") ) {
        #regular expression match first instance of 'one or more digits' into
        # $number
        if ( my ($number) = m/(\d+)/ ) {
            #print if that regex matched
            print $number, "\n";
        }
    }
    

    如果你愿意,你可以单行这个。

    【讨论】:

    • 为什么用 perl 回答 shell 问题?
    • 因为这也是一个regex 的问题,而且并不是大多数基于 Unix 的系统都没有两者。
    猜你喜欢
    • 1970-01-01
    • 2019-03-27
    • 2013-08-17
    • 2016-06-06
    • 1970-01-01
    • 2012-01-25
    • 2010-12-10
    • 1970-01-01
    • 2014-10-17
    相关资源
    最近更新 更多