2

I'm trying to write a commit-msg hook for my git project that checks if commit message accord with a particular style guide. However, it looks like something works differently into the bash world regarding regexp. How could I accomplish my goal?

#!/usr/bin/env bash

read -r -d '' pattern << EOM
(?x)                                      # Enable comments and whitespace insensitivity.
^                                         # Starting from the very beginning of the message
(feat|fix|docs|style|refactor|test|chore) # should be a type which might be one of the listed,
:[ ]                                      # the type should be followed by a colon and whitespace,
(.{1,50})\n                               # then goes a subject that is allowed to be 50 chars long at most,
(?:\n((?:.{0,80}\n)+))?                   # then after an empty line goes optional body each line of which
                                          # may not exceed 80 characters length.
$                                         # The body is considered everything until the end of the message.
EOM

message=$(cat "${1}")

if [[ ${message} =~ ${pattern} ]]; then
  exit 0
else
  error=$(tput setaf 1)
  normal=$(tput sgr0)
  echo "${error}The commit message does not accord with the style guide that is used on the project.${normal}"
  echo "For more details see https://udacity.github.io/git-styleguide/"
  exit 1
fi

I also tried writing this regexp in oneline, like as:

pattern="^(feat|fix|docs|style|refactor|test|chore):[ ](.{1,50})\n(?:\n((?:.{0,80}\n)+))?$"

And even tryed replacing \n with $'\n' but it didn't helped.

1 Answers1

3

Bash supports POSIX extended regular expressions (ERE), not Perl-compatible regexes (PCRE). In particular, (?x) and (?:...) are PCRE.

On a quick look, the one-line version should work if you just replace (?:...) with (...). The "ignore whitespace" function provided by Perl's x modifier isn't available in extended regexes.

See also: Why does my regular expression work in X but not in Y?

ilkkachu
  • 138,973
  • Thank you @ilkkachu , I replaced non-capturing groups with capturing ones but it didn't help so I also replaced \n with $'\n' ("^(feat|fix|docs|style|refactor|test|chore):"$'\s'"(.{1,50})"$'\n'"("$'\n'"((.{0,80}"$'\n'")+))?$"). Now it works for multiline text inlined in variable when replace the message with an actual value but doesn't work with message=$(cat ${file_name}). Could you, please, advise on it? – Denis Verhoturov Sep 20 '19 at 17:43
  • Changed regexp to "^(feat|fix|docs|style|refactor|test|chore):[ ](.{1,50})("$'\n'"("$'\n'"[^"$'\n'"]{0,80})+)?$" - everything works fine now=) – Denis Verhoturov Sep 20 '19 at 18:48
  • @DenisVerhoturov, oh, sorry, I missed the \n. The command substitution in message=$(cat filename) would remove all trailing newlines from the value, which might affect your original regex – ilkkachu Sep 20 '19 at 23:29