git - multiline function as alias is not working

76 views Asked by At

I have written a function which beautify the git log output (to solve the problem mentioned in different color for data and time in git log output).

function gl() {
my_date=();
my_time=();

    while IFS= read -r line; do
        my_date+=( $(date +"%d-%m-%Y" -d @$line) )
        my_time+=($(date +"%H:%M" -d @$line))
    done < <( git log --format="%at" )

    for (( n=0; n<${#my_date[@]}; n++ )); do
        git --no-pager log -1 --skip=$n --pretty=format:"%C(#d33682)%h %C(#859900)${my_date[$n+1]} %C(#b58900)${my_time[$n+1]} %C(#6c71c4)%ce %C(#2aa198)%s";
        printf "\n";
    done

}

So far so good.

Then, I port this function as git alias using the following code in my bash terminal:

git config --global alias.l '!f(){
my_date=();
my_time=();

while IFS= read -r line; do
    my_date+=( $(date +"%d-%m-%Y" -d @$line) )
    my_time+=($(date +"%H:%M" -d @$line))
done < <( git log --format="%at" )

for (( n=0; n<${#my_date[@]}; n++ )); do
    git --no-pager log -1 --skip=$n --pretty=format:"%C(#d33682)%h %C(#859900)${my_date[$n+1]} %C(#b58900)${my_time[$n+1]} %C(#6c71c4)%ce %C(#2aa198)%s";
    printf "\n";
done
}; f'

Now every time I try to use git l, It says f: 2: Syntax error: "(" unexpected (expecting "}").

What might be the issue here?

1

There are 1 answers

0
bk2204 On BEST ANSWER

The script you're writing contains several bashisms. Git invokes /bin/sh, which on your system is not bash. On Debian and Ubuntu, it's dash instead, which is much faster but less featureful.

Debian specifies the features you may expect in /bin/sh, which are basically those found in POSIX, plus test -a and test -o, local, echo -n, and some extensions to kill and trap. These are generally a safe subset of features you may use in /bin/sh on a typical open source operating system.

The first non-portable construct you're using is shell arrays. Those exist only in bash and zsh and are not portable. In addition, the use of the three-part for loop is also a bashism. POSIX sh has only the for name in list syntax. The use of function is similarly non-portable.

The use of process substitution (<()) is also unportable. You'll need to use the git log command as the beginning of a pipeline, but because typically segments of a pipeline are written in subshells, you'll need to be explicit about the scope of the subshell if you want to capture variables correctly.

The way I would write the function is this:

gl() {
    git log --format="%at" | (
    n=0;
    while IFS= read -r line
    do
        date=$(date +"%d-%m-%Y" -d @$line)
        time=$(date +"%H:%M" -d @$line)
        git --no-pager log -1 --skip=$n \
            --pretty=format:"%C(#d33682)%h %C(#859900)$date %C(#b58900)$time %C(#6c71c4)%ce %C(#2aa198)%s%n"
        n=$((n + 1))
    done)
}