【问题标题】:Shell equivalent of php preg_match?Shell相当于php preg_match?
【发布时间】:2010-11-28 08:22:05
【问题描述】:

是否有与 PHP 的 preg_match 等效的 shell?

我正在尝试从 shell 脚本中的该字符串中提取数据库名称。

define('DB_NAME', 'somedb');

在 PHP 中使用 preg_match 我可以做这样的事情。

preg_match('define(\'DB_NAME\','(.*)'\'\)',$matches);
echo $matches[1];

如何在 shell 脚本中完成同样的事情?

【问题讨论】:

    标签: php regex shell grep


    【解决方案1】:

    使用 expr 准确回答问题:

    expr match "string" "regexp"
    

    所以,根据你的需要,你可以写:

    expr match "$mystring" "define('DB_NAME', '\([^']\+\)');"
    

    注意\( \) 对。 如果没有这些字符, expr 将返回匹配字符的数量。 有了它们,只返回匹配的部分。

    $ string="define('DB_NAME', 'toto');"
    $ expr match "$string" "define('DB_NAME', '[^']\+');"
    26
    
    $ string="define('DB_NAME', 'toto');"
    $ expr match "$string" "define('DB_NAME', '\([^']\+\)');"
    toto
    

    不过,我不知道 expr 在哪些环境下可用(并且具有这种行为)。

    【讨论】:

    • 这最好地回答了问题的标题,尽管接受的答案为问题的主体提供了完整的解决方案,尽管没有回答标题问题。值得注意的是,expr 输出匹配字符的数量,并以适合其结果的代码退出,可以直接在测试中使用。但是,在这种情况下,如果您不希望脚本一直吐出匹配数,则应将输出重定向到 /dev/null。
    • 此行为可能取决于使用的版本;但是在 ubuntu 的 bash 下, expr 匹配输出取决于模式中是否有 ( ) 对。如果没有,那么你是对的,它输出匹配的字符数。如果有,则只返回 ( ) 之间匹配的部分。
    【解决方案2】:
    $ t="define('DB_NAME', 'somedb');"
    $ echo $t
    define('DB_NAME', 'somedb');
    $ eval "result=(${t##*,}"
    $ echo $result
    somedb
    $ 
    

    那个确实包含一个 bashism,虽然它可以在大多数开箱即用的环境中工作,但要坚持使用 posix shell 功能,请使用更笨重的版本:

    t="define('DB_NAME', 'somedb');"
    r="${t##*,}"
    r="${r%);*}"
    r=`eval echo $r`
    

    【讨论】:

    • 感谢您的快速回复。 Stackoverflow 非常棒。您是否愿意解释 eval "result=(${t##*,}" 的工作原理?
    • 你在玩这个事实,替代品用');最后,这很好,但不是很多(即:易于修改)但很好......
    • ${t##*,} 删除前缀字符串到 ",",参见 sh(1) 或 bash(1)。这留下了'somedb');为了处理,所以我在前面添加了 result=( 和一个 eval,它去掉了引号并利用了 bash 允许你用 =(...) 进行分配的事实。CB 有点正确,但他错过了这个表达式最糟糕的部分:我认为这是一种 bashism,并且在 posix shell 中不起作用。
    • 当然要感谢 CB 的解决方案:-)
    • 在您的 posix 版本中,如果将其前面的两行替换为 r="${t##*@(,|, )\'}"r="${r%\')*}",则可以消除使用 eval - 请注意,这也可以处理后面没有空格的情况逗号。
    【解决方案3】:

    怎么样:

    $ str="define('DB_NAME', 'somedb');"
    $ php -r "$str echo DB_NAME;"
    somedb
    

    【讨论】:

    • 感谢您的创意解决方案
    【解决方案4】:

    这可能会做你想做的事

    sed -e "/DB_NAME/ s/define('DB_NAME', '\(.*\)');/\1/" /path/to/file/to/search.txt
    

    【讨论】:

      【解决方案5】:

      类似这样的:

      MATCHED=$(sed -n "s/^define('DB_NAME', '\(.*\)')/\1/p" file.php)
      
      if [[ -n ${MATCHED} ]];then
        echo $MATCHED
      else
        echo "No match found"
      fi
      

      【讨论】:

        【解决方案6】:

        只需使用 case/esac 结构

        mystring="define('DB_NAME', 'somedb');"
        case $mystring in
            *define*DB_NAME*) 
              dbname=${mystring%\'*}
              dbname=${dname##*\'}
              echo "$dbname" ;;
        esac
        

        【讨论】:

        • 感谢您的回答。这段代码并不完全符合我的要求。我正在尝试从字符串中提取值。
        • 然后只需进行字符串操作即可在 case/esac 结构中获取 dbname ......没什么太难的......
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-07-19
        • 2015-04-27
        • 2011-08-21
        • 1970-01-01
        • 2016-01-01
        • 2012-12-03
        相关资源
        最近更新 更多