Whenever I do git status, I want to reference the files that were shown easily... whether it be so I can open it in vim, git add it, delete it, git checkout (to revert), etc. So after a bit of looking around, I couldn't find any existing script for this so I made my own. It works, but the code is not pretty, and being a beginner bash scripter (if that's even a noun), I feel like I can do so much better with this.Here is the script:#usage gits: sets env variables $m<n> $d<n> $u<n> $a (modified, deleted, untracked, added)function gits {    git status    gitsall=$(git status -s)    m=$(echo $gitsall | grep ^ M)    d=$(echo $gitsall | grep ^ D)    u=$(echo $gitsall | grep ^??)    a=$(echo $gitsall | grep ^A )    s=$(echo $gitsall | grep ^M )    #i=0    #while [[ -n $(echo {m,d,u}$(($i))) ]]; do#   i=$(($i+1))#   unset {m,d,u}$(($i))#    done    count=1    while read -r tmpfilename; do    tmpfilename=${tmpfilename:2}    set m$(($count))=$(pwd)/$tmpfilename    count=$(($count+1))    done <<< $m    count=1    while read -r tmpfilename; do    tmpfilename=${tmpfilename:2}    set d$(($count))=$(pwd)/$tmpfilename    count=$(($count+1))    done <<< $d    count=1    while read -r tmpfilename; do    tmpfilename=${tmpfilename:3}    set u$(($count))=$(pwd)/$tmpfilename    count=$(($count+1))    done <<< $u    count=1    while read -r tmpfilename; do    tmpfilename=${tmpfilename:3}    set a$(($count))=$(pwd)/$tmpfilename    count=$(($count+1))    done <<< $a    count=1    while read -r tmpfilename; do    tmpfilename=${tmpfilename:3}    set s$(($count))=$(pwd)/$tmpfilename    count=$(($count+1))    done <<< $s    unset m d u a s tmpfilename gitsall}Basically, I call git status -s, save the output as a variable, then grep it to get lists of filenames of modified, deleted, untracked, and added.I then parse each line individually and set $ to the respective file in absolute paths.Now, much of the parsing is the same. Things that vary are env var prefix, substring location (2 or 3 so far), and file list var name. I feel like this can somehow be cleaned up nicely.Note: I do know this is not going to cover everything. Namely, I only so far implemented it for  M  D ?? A , but I know others exist like M , MM, etc. which I eventually plan to address. This script is still a WIP for me but I wanted to clean it up before I add all the change types.I did look around google thinking someone has made something like this because I thought it'll be something people would find convenient. For those who have different workflows that work around my situation, it'll be nice if I can hear them too.Example usage:gitsOutput of git status and set the appropriate varsvim $m1Opens first modified, untracked file in the list from git status
Bash script for referencing git status output files
beginner;bash
Nice tryThat'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 dynamicallyI 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=1set m$c=xecho $m1This 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=1declare m$c=xecho $m1This outputs x alright. Unfortunately, according to help declare:[...] Whenused 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=1printf -v m$c xecho $m1This 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 -sThis 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 contextWhen 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 directoryInstead of $(pwd) it's better to use the $PWD variable.Local variablesInstead 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 sNot 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 implementationPutting 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 <<< $(git status -s)}