代码之家  ›  专栏  ›  技术社区  ›  Amarghosh

在shell脚本中使用正则表达式

  •  24
  • Amarghosh  · 技术社区  · 15 年前

    在Linuxshell脚本中使用正则表达式解析字符串的正确方法是什么?我编写了以下脚本以在控制台上使用 curl sed (不仅仅是因为我很疯狂—我在切换到Linux之前尝试学习一些shell脚本和regex)。

    json=$(curl -s http://stackoverflow.com/users/flair/165297.json)
    echo $json | sed 's/.*"reputation":"\([0-9,]\{1,\}\)".*/\1/' | sed s/,//
    

    但不知何故我觉得 塞德 在这里不是合适的工具。我听说 grep 是关于regex的,并对它进行了一些探索。但很明显,只要找到匹配项,它就会打印整行——我正试图从一行文本中提取一个数字。这是我正在处理的字符串的缩小版本(由返回 卷曲 )。

    “displayname”:“amarghosh”,“reputation”:“2737”,“badgehtml”:“\ u003c span title=\”1银牌\“\u003e\u003c span class=\”badge2 \“\u003e&9679;\u003c/span\u003e\u003c span class=\”badgecount \“\u003e1\u003c/span\u003e\u003c/span\u003e”

    我想我的问题是:

    • 在Linuxshell脚本中使用正则表达式解析字符串的正确方法是什么?
    • 塞德 在这里使用正确的东西?
    • 这个可以用 格雷普 ?
    • 还有其他更简单/更合适的命令吗?
    11 回复  |  直到 7 年前
        1
  •  12
  •   superM    10 年前

    这个 grep 命令将从多个命令中选择所需的行,但不会直接操作该行。为此,你使用 sed 在管道中:

    someCommand | grep 'Amarghosh' | sed -e 's/foo/bar/g'
    

    或者, awk (或 perl 如果有)可以使用。它是比 塞德 在我看来。

    someCommand | awk '/Amarghosh/ { do something }'
    

    对于简单的文本操作,只需使用 grep/sed 联合体。当您需要更复杂的处理时,请继续 AWK 珀尔 .

    我的第一个想法是使用:

    echo '{"displayName":"Amarghosh","reputation":"2,737","badgeHtml"'
        | sed -e 's/.*tion":"//' -e 's/".*//' -e 's/,//g'
    

    它保留了 塞德 进程到一个(您可以使用 -e )

        2
  •  8
  •   user181548    15 年前

    您可能对将Perl用于此类任务感兴趣。作为演示,这里有一个Perl脚本,它打印您想要的数字:

    #!/usr/local/bin/perl
    use warnings;
    use strict;
    use LWP::Simple;
    use JSON;
    
    my $url = "http://stackoverflow.com/users/flair/165297.json";
    my $flair = get ($url);
    my $parsed = from_json ($flair);
    print "$parsed->{reputation}\n";
    

    此脚本要求您安装JSON模块,您只需使用命令即可完成此操作。 cpan JSON .

        3
  •  5
  •   viam0Zah    15 年前

    要在shell脚本中使用JSON,请使用 jsawk 哪一个 像awk,但对于json .

    json=$(curl -s http://stackoverflow.com/users/flair/165297.json)
    echo $json | jsawk 'return this.reputation' # 2,747
    
        4
  •  3
  •   mouviciel    15 年前

    我的主张:

    $ echo $json | sed 's/,//g;s/^.*reputation...\([0-9]*\).*$/\1/'
    

    我在sed参数中输入了两个命令:

    • s/,//g 用于删除所有逗号,尤其是信誉值中的逗号。

    • s/^.*reputation...\([0-9]*\).*$/\1/ 定位行中的信誉值并用该值替换整个行。

    在这种情况下,我发现 sed 提供最紧凑的命令而不丢失可读性。

    用于操作字符串(不仅是regex)的其他工具包括:

    • grep , awk , perl 在大多数其他答案中提到
    • tr 用于替换字符
    • cut , paste 用于处理多列输入
    • bash 它的财富 $(...) 访问变量的语法
    • tail , head 用于保存文件的最后一行或第一行
        5
  •  2
  •   Brian Agnew    15 年前

    sed 是适当的,但您将为每个 塞德 您可以使用(在更复杂的场景中,这可能太重)。 grep 不太合适。它是一个使用regexps查找感兴趣行的搜索工具。

    Perl 是一个合适的解决方案,它是一种具有强大regexp功能的shell脚本语言。它可以完成您所需要的大部分工作,而无需生成单独的进程(与普通的UnixShell脚本不同),并且拥有大量的附加函数库。

        6
  •  2
  •   qba    15 年前

    你可以用grep来做。grep-witch中有-o开关,只提取匹配的字符串而不是整行。

    $ echo $json | grep -o '"reputation":"[0-9,]\+"' | grep -o '[0-9,]\+'
    2,747
    
        7
  •  2
  •   Sinan Ünür    15 年前

    1)在Linuxshell脚本中使用正则表达式解析字符串的正确方法是什么?

    包括正则表达式功能的工具包括sed、grep、awk、perl、python等等。即使是更新版本的bash也具有regex功能。你所要做的就是查找关于如何使用它们的文档。

    2)在这里使用SED是正确的吗?

    可以,但不是必须的。

    3)这可以用grep来完成吗?

    是的,可以。您只需构造类似的regex,就像使用sed或其他方法一样。请注意,grep只做它所做的,如果您想修改任何文件,它不会为您做。

    4)是否有其他更简单/更合适的命令?

    当然。regex可以很强大,但它不一定是每次使用的最佳工具。这也取决于你所说的“简单/合适”的意思。 在regex上使用的另一种方法是使用字段/分隔符方法。你要寻找可以“分裂”的图案。例如,在您的情况下(我下载了165297.json文件,而不是使用curl…(但它是相同的)

    awk 'BEGIN{
     FS="reputation" # split on the word "reputation"
    }
    {
        m=split($2,a,"\",\"")    # field 2 will contain the value you want plus the rest
                                 # Then split on ":" and save to array "a"
        gsub(/[:\",]/,"",a[1])   # now, get rid of the redundant characters
        print a[1]
    }' 165297.json
    

    输出:

    $ ./shell.sh
    2747
    
        8
  •  1
  •   pavium    15 年前

    sed 对于您的任务是完全有效的命令,但它可能不是唯一的命令。

    grep 可能也有用,但正如你所说,它打印了整行。它对于过滤多行文件的行以及丢弃不需要的行最有用。

    高效的shell脚本可以使用命令组合(不仅仅是您提到的两个命令),利用每个命令的才能。

        9
  •  0
  •   Dennis Williamson    15 年前

    Blindly:

    echo $json | awk -F\" '{print $8}'
    

    类似(字段分隔符可以是regex):

    awk -F'{"|":"|","|"}' '{print $5}'
    

    更智能(查找密钥并打印其值):

    awk -F'{"|":"|","|"}' '{for(i=2; i<=NF; i+=2) if ($i == "reputation") print $(i+1)}'
    
        10
  •  0
  •   Sinan Ünür    15 年前

    您可以使用适当的库(如其他人指出的那样):

    E:\Home> perl -MLWP::Simple -MJSON -e "print from_json(get 'http://stackoverflow.com/users/flair/165297.json')->{reputation}"

    $ perl -MLWP::Simple -MJSON -e 'print from_json(get "http://stackoverflow.com/users/flair/165297.json")->{reputation}, "\n"'

    取决于OS/Shell组合。

        11
  •  0
  •   Beejor    7 年前

    通过shell的简单regex

    忽略所讨论的特定代码,有时您可能希望使用类似于javascript的字符串语法,以简单的方式,使用shell快速替换所有从stdin到stdout的regex。

    下面是一些例子,为任何人寻找一种方法做到这一点。Perl在Mac上是个更好的选择,因为它缺少一些SED选项。如果您想将stdin作为一个变量,可以使用 MY_VAR=$(cat); .

    echo 'text' | perl -pe 's/search/replace/g'; # using perl
    echo 'text' | sed -e 's/search/replace/g'; # using sed

    下面是一个自定义的、可重用的regex函数的例子。论点是 源串 (或——对于stdin) 搜索 , 代替 选项 .

    regex() {
        case "$#" in
            ( '0' ) exit 1 ;; ( '1' ) echo "$1"; exit 0 ;;
            ( '2' ) REP='' ;; ( '3' ) REP="$3"; OPT='' ;;
            ( * ) REP="$3"; OPT="$4" ;;
        esac
        TXT="$1"; SRCH="$2";
        if [ "$1" = "--" ]; then [ ! -t 0 ] && read -r TXT; fi
        echo "$TXT" | perl -pe 's/'"$SRCH"'/'"$REP"'/'"$OPT";
    }
    

    echo 'text' | regex -- search replace g;