【问题标题】:Get substring using either perl or sed使用 perl 或 sed 获取子字符串
【发布时间】:2019-08-11 13:44:35
【问题描述】:

我似乎无法正确获取子字符串。

declare BRANCH_NAME="bugfix/US3280841-something-duh";

# Trim it down to "US3280841"
TRIMMED=$(echo $BRANCH_NAME | sed -e 's/\(^.*\)\/[a-z0-9]\|[A-Z0-9]\+/\1/g')

这仍然返回bugfix/US3280841-something-duh

如果我尝试使用 perl:

declare BRANCH_NAME="bugfix/US3280841-something-duh";

# Trim it down to "US3280841"
TRIMMED=$(echo $BRANCH_NAME | perl -nle 'm/^.*\/([a-z0-9]|[A-Z0-9])+/; print $1');

什么都不输出。

我做错了什么?

【问题讨论】:

    标签: regex bash perl sed


    【解决方案1】:

    你可以使用这个sed:

    sed -E 's~^.*/|-.*$~~g' <<< "$BRANCH_NAME"
    

    US3280841
    

    这个awk

    awk -F '[/-]' '{print $2}' <<< "$BRANCH_NAME"
    

    US3280841
    

    【讨论】:

      【解决方案2】:
      sed 's:[^/]*/\([^-]*\)-.*:\1:'<<<"bugfix/US3280841-something-duh"
      

      【讨论】:

        【解决方案3】:

        仅使用 bash 参数扩展:

        $: # don't use caps; see below.
        $: declare branch="bugfix/US3280841-something-duh"
        $: tmp="${branch##*/}"
        $: echo "$tmp"
        US3280841-something-duh
        $: trimmed="${tmp%%-*}" 
        $: echo "$trimmed"
        US3280841
        

        这意味着:

        $: tmp="${branch_name##*/}"
        $: trimmed="${tmp%%-*}" 
        

        在不产生额外进程的情况下分两步完成工作。

        sed

        $: sed -E 's#^.*/([^/-]+)-.*$#\1#' <<< "$branch"
        

        这表示“在任何或没有字符后跟一个斜线,记住一个或多个不是斜线或破折号,然后是一个不记得的破折号,然后是任何或没有字符,然后用记住的部分替换整个输入。”

        你原来的模式是

        's/\(^.*\)\/[a-z0-9]\|[A-Z0-9]\+/\1/g'
        

        这表示“记住任意数量的任何内容,后跟斜杠,然后是小写字母或数字,然后是管道字符(因为它们只能与 -E 一起使用),然后是大写字母或数字,然后是文字加号,然后将其全部替换为您记得的内容。”

        GNU 的manual 是你的朋友。我一直在查资料,以确保我做对了。有时候还是要试几次,哈哈。

        顺便说一句 - 尽量不要使用全大写的变量名。这是一个约定,表明它对操作系统来说是特殊的,比如 RANDOM 或 IFS。

        【讨论】:

        • 赞成您的答案,因为我通常喜欢避免调用 sed 等人进行简单的字符串转换。尽管如此,bash 并没有提供一种简单的单行方式来对变量进行正则表达式替换,这让我感到困扰。对于bash 中的单行,我能想到的最好的方法是非常丑陋的branch=$([[ "$branch" =~ ^.*/([^-]+)-.*$ ]] &amp;&amp; echo "${BASH_REMATCH[1]}")。我希望bash 能给我们提供类似于perl$s =~ s/pattern/subst/; 的东西,但是bash${parameter/pattern/subst} 扩展AFAIK 不会说正则表达式。
        • 可以输入tmp="${branch##*/}" &amp;&amp; trimmed="${tmp%%-*}"。但是,是的。我理解,但我同意。
        • 是的,这不仅仅是将所有内容塞进一行。理想情况下应该是一个 操作 需要 bash 中的多个操作。
        【解决方案4】:

        Perl 版本只是将+ 放在错误的位置。它应该在捕获括号内:

        TRIMMED=$(echo $BRANCH_NAME | perl -nle 'm/^.*\/([a-z0-9A-Z]+)/; print $1');
        

        【讨论】:

          【解决方案5】:

          只需在A-Z0-9 之前使用^

          TRIMMED=$(echo $BRANCH_NAME | sed -e 's/\(^.*\)\/[a-z0-9]\|[^A-Z0-9]\+/\1/g')
          

          在您的 sed 案例中。

          你也可以简单地使用

          TRIMMED=$(echo $BRANCH_NAME | sed "s/[a-z\/\-]//g" )
          

          也是。

          【讨论】:

            【解决方案6】:

            在 shell 终端上输入

            $ BRANCH_NAME="bugfix/US3280841-something-duh"
            
            $ echo $BRANCH_NAME| perl -pe 's/.*\/(\w\w[0-9]+).+/\1/'
            

            使用 s(替代)命令代替 m(匹配)
            perl 是 sed 的超集,所以它是相同的 'sed -E' 而不是 'perl -pe'

            【讨论】:

              【解决方案7】:

              另一个使用 Perl 正则表达式字符类的变体(参见perldoc perlrecharclass)。

              echo $BRANCH_NAME | perl -nE 'say m/^.*\/([[:alnum:]]+)/;'
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2015-11-18
                • 2012-02-09
                • 2017-01-31
                • 2012-03-13
                相关资源
                最近更新 更多