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

时间:2009-10-28 10:21:59

标签: regex linux shell

在linux shell脚本中使用正则表达式解析字符串的正确方法是什么?我编写了以下脚本,使用curlsed在控制台上打印我的SO代表(不仅仅是因为我反复疯狂 - 我试图在切换到之前学习一些shell脚本和正则表达式的Linux)。

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

但不知怎的,我觉得sed不适合在这里使用。我听说grep完全是关于正则表达式并且稍微探讨了一下。但显然它会在找到匹配时打印整行 - 我试图从单行文本中提取一个数字。这是我正在处理的字符串的缩小版本(由curl返回)。

  

{“displayName”:“Amarghosh”,“声誉”:“2,737”,“badgeHtml”:“\ u003cspan title = \”1银徽章\“\ u003e \ u003cspan class = \”badge2 \“\ u003e& #9679; \ u003c / span \ u003e \ u003cspan class = \“badgecount \”\ u003e1 \ u003c / span \ u003e \ u003c / span \ u003e“}

我想我的问题是:

  • 在linux shell脚本中使用正则表达式解析字符串的正确方法是什么?
  • sed在这里使用是正确的吗?
  • 可以使用grep完成吗?
  • 是否有更容易/更合适的其他命令?

11 个答案:

答案 0 :(得分:12)

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

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

或者,可以使用awk(或perl,如果可用)。在我看来,它是一个比sed更强大的文本处理工具。

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

对于简单的文本操作,只需坚持使用grep/sed组合。如果您需要更复杂的处理,请前往awkperl

我的第一个想法就是使用:

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

sed进程的数量保持为1(您可以使用-e提供多个命令)。

答案 1 :(得分:8)

您可能有兴趣将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即可完成。

答案 2 :(得分:5)

要在shell脚本中使用JSON,请使用{em>类似于awk的jsawk,但是对于JSON 。

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

答案 3 :(得分:3)

我的主张:

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

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

  • s/,//g用于删除所有逗号,特别是声誉值中包含的逗号。

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

在这种特殊情况下,我发现sed提供了最紧凑的命令而不会降低可读性。

其他用于操作字符串的工具(不仅仅是正则表达式)包括:

    大多数其他答案中提到的
  • grepawkperl
  • tr用于替换字符
  • cutpaste用于处理多列输入
  • bash本身及其丰富的$(...)语法,用于访问变量
  • tailhead用于保存文件的最后一行或第一行

答案 4 :(得分:2)

sed是合适的,但是您将为您使用的每个sed生成一个新进程(在更复杂的情况下可能过于重量级)。 grep并不合适。这是一个使用regexp查找感兴趣的行的搜索工具。

Perl是一个合适的解决方案,是一种具有强大正则表达式功能的shell脚本语言。它可以完成你需要的大部分工作而不会产生独立的进程(与普通的Unix shell脚本不同),并且拥有庞大的附加功能库。

答案 5 :(得分:2)

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

$ echo $json | grep -o '"reputation":"[0-9,]\+"' | grep -o '[0-9,]\+'
2,747

答案 6 :(得分:2)

  

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

包含正则表达式功能的工具包括sed,grep,awk,Perl,Python等等。即使是较新版本的Bash也具有正则表达式功能。您需要做的就是查找有关如何使用它们的文档。

  

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

它可以,但不是必需的。

  

3)可以使用grep吗?

完成

是的,它可以。你将使用sed或其他方法构建类似的正则表达式。请注意,grep只是执行它所做的事情,如果你想修改任何文件,它将不会为你做。

  

4)是否还有其他命令更容易/更合适?

当然。正则表达式可以是强大的,但它不一定是每次使用的最佳工具。它还取决于“更容易/适当”的含义。 在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

答案 7 :(得分:1)

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

grep也可能有用,但正如你所说它打印整行。它最有用的是过滤多行文件的行,并丢弃你不想要的行。

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

答案 8 :(得分:0)

盲目:

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

类似(字段分隔符可以是正则表达式):

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

更聪明(查找密钥并打印其值):

awk -F'{"|":"|","|"}' '{for(i=2; i<=NF; i+=2) if ($i == "reputation") print $(i+1)}'

答案 9 :(得分:0)

您可以使用合适的库(如其他人所述):

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组合。

答案 10 :(得分:0)

通过Shell进行简单的RegEx

忽略有问题的特定代码,有时你可能想要使用类似于JavaScript的字符串语法以简单的方式使用shell从stdin到stdout进行快速正则表达式替换。

下面是一些寻找方法的人的例子。由于缺少一些sed选项,Perl在Mac上是更好的选择。如果您想将stdin作为变量,可以使用MY_VAR=$(cat);

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

这是一个自定义,可重用的正则表达式函数的示例。参数是源字符串(或 - 对于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;