Bash script for referencing git status output files
Nice try

That's a fantastic idea.
It's very annoying to run git status and then very often type some next command and copy paste selected files from the output.
I long wanted to have something like this but never made time to actually do it.
You gave me the final push, so thanks.

Setting variables dynamically

I don't think your script actually works :-)
At least on my computer, in Bash 3 or 4,
it's not possible to create variables dynamically with set,
for example:

m1=
c=1
set m$c=x
echo $m1


This outputs nothing, because set m$c=x does not actually perform m1=x.

After some research, I found that this works with declare:

m1=
c=1
declare m$c=x
echo $m1


This outputs x alright. Unfortunately, according to help declare:


[...] When
used in a function, makes NAMEs local, as with the `local' command.



That is, the variables created dynamically this way inside the function will not be visible outside, so this is not usable for this purpose.

One obvious option is eval, but not a good one, because eval is evil.
A well-crafted filename in the working tree could wreak havoc.
Even if this is unlikely, I would rather not resort to such option.

Finally, there's a trick with printf -v that will work well:

m1=
c=1
printf -v m$c x
echo $m1


This outputs x, and even when used in a function, m1 will be visible outside.
The only downside is that printf is not POSIX compliant,
but that's probably not a big problem in practice.

Unnecessary repeated processing of git status -s

This is really quite wasteful:


m=$(echo "$gitsall" | grep "^ M")
d=$(echo "$gitsall" | grep "^ D")
u=$(echo "$gitsall" | grep "^??")
a=$(echo "$gitsall" | grep "^A ")
s=$(echo "$gitsall" | grep "^M ")



It would be better to run git status -s just once,
loop over the output,
use a case statement to decide the type of the change,
and set the m, d, u, a, s variables accordingly.

When you go this way, you can also directly create the variables with a count, so that you don't need all those repetitive while loops for each status type.

Arithmetic context

When within $((...)), you don't need to write $ to access the values of variables, for example instead of:


count=$(($count+1))



You can write:

count=$((count+1))


An even shorter equivalent:

((count++))


Current working directory

Instead of $(pwd) it's better to use the $PWD variable.

Local variables

Instead of using the unset command at the end of the function to clear the variables used, it's much better to use local variables, for example:

local m d u a s


Not only this will make sure you don't clear the variables,
it also makes your use correct.
The current use is not correct,
because if some of these variables had value before calling the function,
the values get reset.
When using local, the original values of those variables remain intact in the calling environment.

Alternative implementation

Putting the above together,
the function could be written simpler as:

gits() {
    git status
    mc=1 dc=1 uc=1 ac=1 sc=1
    local line status path name
    while read -r line; do
        [ "$line" ] || continue
        status=${line:0:2}
        path=${line:3}
        case "$status" in
            " M") name=m$((mc++)) ;;
            " D") name=d$((dc++)) ;;
            "??") name=u$((uc++)) ;;
            "A ") name=a$((ac++)) ;;
            "M ") name=s$((sc++)) ;;
            *) echo unsupported status on line: $line
        esac
        printf -v $name "$path"
    done &lt;&lt;&lt; "$(git status -s)"
}