0

I'm trying to do a hook for a message that you're about to commit on git. What I usually do when about to commit is [SOME_DESCRIPTION] Refs #[0-9]+

I've never done shell scripting before but I'm fairly adept at programming in general. I'm trying to write a script in commit-msg that will validate if the current that you're trying to save has the pattern "*Refs #[0-9]+". But I have no shell syntax experience and not too much linux.

  • I think $1 is to get the current commit message, but I'm probably wrong.
  • And my way of checking for the pattern is probably way wrong
requireTicketRef=$1
if [[ $requireTicketRef == *Refs \#[0-9]+ ]]
then
    echo "Contains ticket reference"
    exit 0
else
    echo "Need to add ticket reference"
    exit 1
fi

1 Answer 1

1

Assuming you're right about $1 being the commit message, your code is close, but the patterns that bash uses with == in [[...]] are not regular expressions. They are instead the same sort of wildcards used to expand filenames, usually called "globs", which don't normally have the ability to quantify specific matches (like "1 or more digits").

(They also have to be a single word, so you need another backslash in front of the space between Refs and the #. And you actually don't need one in front of the # when it's not the first thing in a word.)

You have a couple options to fix this. The simplest is probably to use actual regular expressions, which you can do inside [[...]] by just using =~ instead of ==:

if [[ ! $requireTicketRef =~ Refs\ #[0-9]+ ]]; then 
  echo >&2 "Need to add ticket reference."
  exit 1
fi

The other option would be to turn on the extglob ("extended glob") option, which borrows some syntax from the Korn shell to bring regex-like capabilities (negation, alternation, quantification) to glob patterns.

shopt -s extglob
if [[ ! $requireTicketRef == *Refs\ #+([0-9])* ]]; then 
  echo >&2 "Need to add ticket reference."
  exit 1
fi
Sign up to request clarification or add additional context in comments.

5 Comments

There are a few details not quite correct here: 1) There is a =~ regex operator for [[, so if it is available in your version you can use regexes. 2) You don't have to escape the space/# if you don't want to, you can use a more readable *"Refs #"+([0-9]) instead. 3) You do not have to specify extglob on the shebang line, because bash does not parse the whole script at a time, it parses blockwise and your example works for me if you enable it at the beginning (more here). 3) The first if is very sad since there is a semicolon missing ;-)
I also just read in the bash changelog that extglob is always on (!) if you use [[ with == or != since bash-4.1-alpha (probably for ksh compatibility), so with any recent version it seems you only need the extglob option for single bracket notation [. Not something you will want to rely on for compatibility with older bash versions, but good to know since this is nowhere mentioned in the manpage.
@AdrianFrühwirth - I'd say putting double quotes around "Refs #" counts as escaping the space. :) Thanks for the correction on the semicolon and the extglob setting. As for the =~ operator, I should have mentioned it, but I'm staying away from Bash 4isms until it becomes more ubiquitous. Which, given the proliferation of Macs among my colleagues, probably means "until it ships in /bin on OS X".
Under Linux, unfortunately, you can't put #!/bin/bash -O extglob into the shebang, because Linux passes the rest of the shebang as a single arg (a single string), and bash thinks it has been given a space as a short option (interprets "-O " as "-O" and "- ", but space is an invalid short option).
Thanks for the comments, all. Massively rejiggered the answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.