使用正则表达式将 bash 脚本转换为 sh



我真的在努力编写Bourne shell脚本。基本上,我有三种输入格式用于我尝试检测的名为"ref"的变量:

    ref="refs/head/
  1. .*"(即以"refs/head/"开头,我对斜杠后面的位感兴趣(
  2. ref="refs/tags/
  3. .*"(即以"refs/tags/"开头,我对斜杠后面的位感兴趣(
  4. 其他所有内容(即忽略不以"refs/head/"或"refs/tags/"开头的所有内容(

例如

如果 ref="refs/head/master",设置 TAG="master">

如果 ref="refs/tags/0.2.4",则设置 TAG="0.2.4">

对于其他所有内容,设置 TAG=">

现在我用bash shell写了一些东西,但我真的很难将其转换为Bourne(#!/bin/sh(:

#!/bin/bash
#
#This works!
#
TAG=""
re='^refs/head/.*'   #regex: begins with refs/head/, ends with anything
re2='^refs/tags/.*'   #regex: begins with refs/tags/, ends with anything
if [[ $ref =~ $re ]]; then
        #do nothing - OK
        true   #NOP
else    
        #check if it's a tag update
        if [[ $ref =~ $re2 ]]; then
                TAG=${$ref##*/}   #looks worse that it is: http://stackoverflow.com/questions/3162385/how-to-split-a-string-in-shell-and-get-the-last-field
        fi
        exit 0
fi
echo $TAG

我花了很长时间才a(编写这个程序和b(找出为什么我的程序会发疯 - 结果我需要#!/bin/sh而不是#!/bin/bash

我怎样才能把它转换为sh?也许其他人对我的正则表达式体操有更优雅的解决方案?


更新:

感谢您到目前为止的回答(尤其是@gboffi(。我想我快到了。

我现在需要知道$TAG是否来自"refs/head/","refs/tags/"或两者都不是。我试图修改一些答案,但真的很挣扎。我需要离开并从第一原则中更多地了解sh,而不是试图破解它。

更新 2:

所以睡了一夜后,我在大约20分钟内就想通了。这是我的解决方案:

#!/bin/sh
ref="refs/asdf/master"
TAG=""
TAG="${ref#refs/heads/}"
if [ "$ref" != "${ref#refs/heads/}" ]; then
        echo "heads"
        echo $TAG
else
        TAG="${ref#refs/tags/}"
        if [ "$ref" != "${ref#refs/tags/}" ]; then
                echo "heads"
                echo $TAG
        else
                TAG=""
        fi
fi
echo "--->$TAG"

我相信有一个更优雅的解决方案;但我就是没有时间!

这是一个函数,在dash中定义(sh的Linux版本(

% dash
$ tag() {
>  TAG=""
>  [ "$1" != "${1#refs/head/}" ] && TAG="${1#refs/head/}"
>  [ "$1" != "${1#refs/tags/}" ] && TAG="${1#refs/tags/}"
>  echo "$TAG"
>}
$ tag poldo
$ tag refs/head/poldo
poldo
$ tag refs/tags/pippo
pippo
$ tag to093u0refs/head/poldo
$exit
% 

处理此问题的最惯用方法是使用 case 语句和模式匹配:

#!/bin/sh
case $ref in
  refs/head/*) true ;;                       # original behavior: no output, success
  refs/tags/*) printf '%sn' "${ref##*/}" ;; # original behavior: emit output
  *) false # exit with an error              # original code didn't specify behavior
esac

对于refs/head/*refs/tags/*都不匹配的情况,我退出错误的原因是,如果您想在这种情况下成功退出,则可以完全省略refs/head/*测试。

您可以使用

rev-parse,以下是我的一个示例存储 库。请注意,最后一个不按预期生成输出。

$ git rev-parse --abbrev-ref refs/heads/master主人$ git rev-parse --abbrev-ref refs/tags/55$ git rev-parse --abbrev-ref @^

阅读了您对所需函数的描述后,似乎可以归结为:

  1. 检查输入参数。 如果它以 refs/head 或 refs/master 开头,请继续,否则停止。
  2. 获取终端信息并将变量 TAG 设置为它。

因此,假设您的输入在变量 REF 中,

TAG=""
echo $REF | egrep -q 'refs/head|refs/master'
if [ $? -eq 0 ]
then
  TAG=`echo $REF | sed "s/.*///"`
fi

应该这样做。

(壳头的旁注:在这种特殊情况下,basename 是比 sed 更好的解决方案吗?

最新更新