0

I have this function:

git_commit () {
    if [[ $# -eq 0 || ( $# -eq 1 && $1 == '.' ) ]]
    then
        git commit .
    else
        commit_string=''
        for var in "$@"
        do
      ! [[ $var =~ ^[0-9]+$ ]] && { echo "Supply integer values from the menu only. Nothing added." && return; }
      file="$(git status -s|awk 'FNR == '$var'{$1="";print $0}')";
      file=$(sed -e 's/^[[:space:]]*//' <<<"$file")
      new_file="${file} "
      commit_string+=${new_file}

        done
    echo $commit_string;
        read -ep "Commit description: " desc
    commit_string=${commit_string##*( )}
    commit_string="${commit_string//\"}"
    git commit -m "$desc" ${commit_string}
    fi
  git_short_status

}

The function generates a string comprised of filenames that I select with a menu. Example:

get_commit 1 3 5

In this case, it would run:

git commit -m 'description from prompt' file_1 file file_3 file_5

I'm having a tough time figuring out how to get the function to handle files with spaces in them. The problem is in this line:

git commit -m "$desc" ${commit_string}

This line works fine for multiple files with no spaces. However, it chokes on a single file with spaces in it. So I changed it to:

git commit -m "$desc" "${commit_string}"

Like this, it works for files with spaces in it but chokes when I have multiple files (I get an error that it doesn't recognize the file path.

2 Answers 2

3

Embedding escapes, quotes, etc in variables doesn't work right, because the shell parses escapes etc before it expands variables; as a result, by the time the escape/whatever is part of the command, it's too late for it to do anything useful.

If you need to store multiple items (e.g. filenames) in a variable, the better way to do it is to use an array, store each item as a separate array element, and then expand the array with the syntax "${arrayname[@]}".

I'm not sure how git status -s reports files with spaces, but I think this should work:

git_commit () {
    if [[ $# -eq 0 || ( $# -eq 1 && $1 == '.' ) ]]
    then
        git commit .
    else
        commit_array=()    # This creates an empty (zero-element) array
        for var in "$@"
        do
      ! [[ $var =~ ^[0-9]+$ ]] && { echo "Supply integer values from the menu only. Nothing added."; return; }
      file="$(git status -s|awk -v var="$var" 'FNR == var {$1="";print $0}')";
      file=$(sed -e 's/^[[:space:]]*//' <<<"$file")
      commit_array+=("${file}")    # Add a new element. The +=, (), and double-quotes are required for this to work right.

        done
    printf "%q " "${commit_array[@]}"    # Print the elements in "quoted" form
    echo    # The printf doesn't print a newline; so do that
        read -ep "Commit description: " desc
    git commit -m "$desc" "${commit_array[@]}"
    fi
  git_short_status

}

I also changed the && to ; in the error return, since if the echo somehow manages to fail, you still want to return rather than continuing. Also, I changed the way $var is passed to awk to a safer form (although in this case it doesn't really matter). (Actually, the whole awk ... sed bit could be cleaned up a bit, but I'll leave it...)

Sign up to request clarification or add additional context in comments.

Comments

0

This solved the problem:

bash -c "git commit -m \"$desc\" ${commit_string}"

Though I'm not quite sure why.

Comments

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.