在文件中的多行上查找多个字符串并使用bash / perl操作输出

时间:2014-03-18 03:49:22

标签: perl bash shell

我正在尝试获取托管在我服务器上的内容管理系统的版本号。如果版本号存储在一行上,我可以相当简单地做到这一点:

grep -r "\$wp_version = '" /home/

它返回了我想要的标准输出:

/home/$RANDOMDOMAIN/wp-includes/version.php:$wp_version = '3.7.1';

我遇到的问题是当我开始寻找存储在两条或更多条线上的版本号时,比如Joomla!或Magento分别使用以下格式:

的Joomla:

/** @var  string  Release version. */
public $RELEASE = '3.2';

/** @var  string  Maintenance version. */
public $DEV_LEVEL = '3';

的Magento:

'major'     => '1',
'minor'     => '8',
'revision'  => '1',
'patch'     => '0',

我已经在某种程度上使用以下方法工作了(如果由于某种原因,我正在寻找的其中一个字符串缺少整个命令就会变得无用,因此使用此方法xargs -l3期望在-print)提供的路径上方2行:

find /home/ -type f -name version.php -exec grep " \$RELEASE " '{}' \; -exec grep " \$DEV_LEVEL " '{}' \; -print | xargs -l3 | sed 's/\<var\>\s//g;s/\<public\>\s//g' | awk -F\; '{print $3":"$1""$2}' | sed 's/ $DEV_LEVEL = /./g'

我的输出是这样的:

/home/$RANDOMDOMAIN/version.php:$RELEASE = 3.2.3
/home/$RANDOMDOMAIN/anotherfolder/version.php:$RELEASE = 1.5.0

我还有一个for循环,它将排除任何不包含两个字符串的文件,但是根据它需要筛选的数量,可能比上面的查找一个内容要长得多:

for path in $(grep -rl " \$RELEASE " /home/ 2> /dev/null | xargs grep -rl " \$DEV_LEVEL ")
    do
        joomlaver="$path"
        joomlaver+=$(grep " \$RELEASE " $path)
        joomlaver+=$(echo " \$DEV_LEVEL = '$(grep " \$DEV_LEVEL " $path | cut -d\' -f2)';")
        echo "$joomlaver" | sed 's/\<var\>\s//g;s/\<public\>\s//g;s/;//g' | awk -F\' '{ print $1""$2"."$4 }' | sed 's/\s\+//g'
        unset joomlaver
done

我的输出是这样的:

/home/$RANDOMDOMAIN/version.php$RELEASE=3.2.3
/home/$RANDOMDOMAIN/anotherfolder/version.php$RELEASE=1.5.0

但我必须相信有一种更简单,更短,更优雅的方式。 Bash是首选,或者如果它可以用perl one衬里完成,那也可以。任何和所有的帮助将不胜感激。提前致谢。 (对不起,所有的编辑,但我也试图自己解决这个问题!)

1 个答案:

答案 0 :(得分:0)

这是一个perl单行程序,它将从您显示的php文件格式中提取$ RELEASE和$ DEV_LEVEL:

perl -ne '$v=$1 if /\$RELEASE\s*=\s*\047([0-9.]+)\047/; $devlevel=$1 if /\$DEV_LEVEL\s*=\s*\047([0-9.]+)\047/; if (defined $v && defined $devlevel) { print "$ARGV: Release=$v Devlevel=$devlevel\n"; last; }'

-n使perl有效地将整个事物包装在while (<>) { }循环中。针对两个正则表达式检查每一行。如果它们都匹配,那么它将打印结果并退出。

\ 047用于匹配单引号,否则shell会混淆。

如果找不到匹配项,则不会打印任何内容。否则它打印出这样的东西:

sample.php: Release=3.2 Devlevel=3

您可以将它与find和xargs结合使用来遍历目录结构,可能是这样的:

find . -name "*.php" | xargs perl -ne '$v=$1 if /\$RELEASE\s*=\s*\047([0-9.]+)\047/; $devlevel=$1 if /\$DEV_LEVEL\s*=\s*\047([0-9.]+)\047/; if (defined $v && defined $devlevel) { print "$ARGV: Release=$v Devlevel=$devlevel\n"; last; }'

你可以为你提到的其他文件格式(Magento?)制作一个类似的版本。