在shell脚本中使用正则expression式

在linux shell脚本中使用正则expression式parsingstring的正确方法是什么? 我写了下面的脚本来使用curlsed在控制台上打印我的SO代码(不仅仅是因为我是rep-crazy-我想在学习linux之前学习一些shell脚本和正则expression式)。

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

但不知何故,我觉得sed是不适合在这里使用的工具。 我听说grep是关于正则expression式,并探讨了一下。 但显然它打印整个行,每当发现匹配 – 我试图从一行文本中提取一个数字。 这里是我正在处理的string的缩小版本(由curl返回)。

{“displayName”:“amarghosh”,“信誉”:“2,737”,“badgeHtml”:“\ u003cspan title = \”1银徽章\“\ u003e \ u003cspan class = \”badge2 \“\ u003e● \ u003c / span \ u003e \ u003cspan class = \“badgecount \”\ u003e1 \ u003c / span \ u003e \ u003c / span \ u003e“}

我想我的问题是:

  • 在linux shell脚本中使用正则expression式parsingstring的正确方法是什么?
  • sed是正确的东西在这里使用?
  • 这可以使用grep来完成吗?
  • 还有其他的命令更容易吗?

Solutions Collecting From Web of "在shell脚本中使用正则expression式"

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给出多个命令)。

您可能有兴趣使用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

为了在shell脚本中使用JSON,使用类似于awk的 jsawk ,但使用JSON

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

我的主张:

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

我把两个命令在sed参数中:

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

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

在这个特殊情况下,我发现sed提供了最简洁的命令,而不会丢失可读性。

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

  • grepawkperl在大多数其他答案中提到过
  • tr替换字符
  • cutpaste以处理多列输入
  • 用自己丰富的$(...)语法来访问变量
  • tailhead保持文件的最后或第一行

sed是合适的,但是你会为每个使用的sed产生一个新的进程(在更复杂的场景中这可能太重了)。 grep并不适合。 这是一个搜索工具,使用正则表达式找到感兴趣的线。

在这里Perl是一个合适的解决方案,是一个具有强大正则表达式功能的shell脚本语言。 它将完成你所需要的大部分工作,而不需要产生分离的进程(与普通的Unix shell脚本不同),并且有一个巨大的附加函数库。

你可以用grep来完成。 grep女巫提取只有匹配的字符串不是整行。

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

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

包含正则表达式功能的工具包括sed,grep,awk,Perl,Python等等。 甚至更新版本的Bash都有正则表达式的能力。 所有你需要做的就是查阅如何使用它们的文档。

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

它可以,但不是必需的。

3)可以用grep来完成吗?

是的,它可以。 你会像使用sed或其他构造一样构造类似的正则表达式。 请注意,grep只是做它做的,如果你想修改任何文件,它不会为你做。

4)有没有其他的命令更容易/更合适?

当然。 正则表达式可以是强大的,但它不一定是每次使用的最佳工具。 这也取决于你的意思是“简单/合适”。 另一种在正则表达式上使用最少的方法是使用fields / delimiter方法。 你寻找可以“分裂”的模式。 例如,在你的情况(我已经下载了165297.json文件,而不是使用卷曲..(但它是相同的)

 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 

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

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

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

一味地:

 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)}' 

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

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

简单的RegEx通过Shell

不管有问题的特定代码,可能有些时候你想用一个简单的方法,使用一个类似于JavaScript的字符串语法,使用shell来执行快速的正则表达式替换 – 从标准输入到标准输出。

以下是一些寻找方法的例子。 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() { 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;