Home > Enterprise >  bash regexp that match to character sequence
bash regexp that match to character sequence

Time:01-22

I am writing a bash script that receives <task> ID strings as a parameter and then executes the specified tasks. At the end of the execution, it must show the total execution time. The code must be flexible, and easy to add new conditions.

Usage: build.sh <task><task><task>...

The task id is a little bit tricky:

  • if it is only a character [a-z] then it represents all subtasks of the given task
  • if it is a character a number, it represents only the specific subtask

Let me give you some examples:

  • build.sh a1a2: execute tasks of a1 and a2, but not a3
  • build.sh a: execute all tasks starts with char a (all subtasks of a)
  • build.sh a1b: run only task a1 and all subtasks of b
  • build.sh a1b3: run only task a1 and b3
  • build.sh ab: run all subtasks of a and b
  • build.sh *: run all tasks defined is the build script (all subtasks), like a b c

The execution order of the tasks is pre-defined, so actually b1a1 will execute a1b1.

This is my bash script:

#!/bin/bash -ue

# show help
function show_help() {
    if [ "$1" -eq 0 ]; then
        printf "..."
        exit 0
    fi
}

# does the build
function build {
    local title dir
    title="$1"
    dir="$2"
    printf "\n%b> building '%s'...%b\n" "$COLOR_YELLOW" "$title" "$COLOR_DEFAULT"
    cd "$WORKSPACE/../$dir"
    ./build.sh
    cd "$WORKSPACE"
}

# group A build
function build_group_a {
    if [[ "$1" == *a1* ]]; then build "task A.1" "base/xxx"; fi
    if [[ "$1" == *a2* ]]; then build "task A.2" "base/yyy"; fi
    if [[ "$1" =~ $(getRegexp a) ]]; then
      build "task A.1" "base/xxx"
      build "task A.2" "base/yyy"
    fi
}

# group B build
function build_group_b {
   # same with 'build_group_a' only conditions are different
}

# REGEXP THAT DOES NOT WORK PROPERLY
function getRegexp() {
    printf ".*%s[a-z].*" "$1"
}


show_help "$#"
START_TIME=$(date  %s)

# 'all' works but '*' not
if [[ "$1" == all ]]; then
    build_group_a a
    build_group_b b
else
    build_group_a "$1"
    build_group_b "$2"
fi

ELAPSED=$(($(date  %s) - START_TIME))
printf "build time: %s\n" "$(date -d@$ELAPSED -u  %H\ hour\ %M\ day\ %S\ sec)"

Everything works fine, tasks are executed properly in order but if I use build.sh a then nothing is executed. If I use build.sh ab, only tasks a are executed. I do not know why. It seems that the last task-ID is not processed by my regexp.

Another issue is that if I say build.sh aa1 then all tasks for a are executed but task a1 twice. Task a1 must only be executed once when a is called.

That could be great if you can guide me on how to fix the problem in my regular expression.

CodePudding user response:

On the regex part, you can try this :

#!/usr/bin/env bash

input="$1"
pattern='(\*|[[:alpha:]][[:digit:]]?)'
while [[ $input =~ $pattern ]]; do
    echo "Argument passed : ${BASH_REMATCH[1]}"
    input="${input:${#BASH_REMATCH[0]}}" # next iteration
done

test with :

bash build.sh a1b
bash build.sh "*"

CodePudding user response:

Thanks a lot for your comments. Based on your help I was able to fix the issue. In the final version I use a little bit different approach for the regexp than before. And in the meanwhile I simplified everything.

This is the code with the regexp:

#!/bin/bash -ue

function build {
    local arg id title dir group regexp
    arg=$(printf "%sz" "$1")
    id="$2"; title="$3"; dir="$4"; group=${id:0:1}
    regexp=$(printf "(0|%s|%s[a-z])" "$id" "$group")
    if [[ "$arg" =~ $regexp ]]; then
        printf "%b> building '%s'...%b\n" "$COLOR_YELLOW" "$title" "$COLOR_DEFAULT"
        cd "$WORKSPACE/.../$dir"
        ./build.sh
        cd "$WORKSPACE"
    fi
}

function show_help() {
    if [ "$1" -eq 0 ]; then
        printf "..."
        exit 0
    fi
}

...
show_help "$#"
START_TIME=$(date  %s)

build "$1" "a1" "task A.1" "aa/xxx"
build "$1" "a2" "task A.2" "aa/yyy"
build "$1" "b1" "task B.1" "bb/vvv"
build "$1" "b2" "task B.2" "cc/www"

ELAPSED=$(($(date  %s) - START_TIME))
printf "build time: %s\n\n" "$(date -d@$ELAPSED -u  %H\ hour\ %M\ day\ %S\ sec)"

This works like a charm and I think that it is enough simple.

I use 0 to run all of the tasks because unfortunately, the asterisk(*) was not working for me in my regexp. Another trick that I had to do is to add an extra character (in my case it is an z) at the end of the user input. That was necessary, otherwise, the last command won't be executed.

  •  Tags:  
  • bash
  • Related