3

I am trying to implement this helper bash function:

ores_simple_push(){(

set -eo pipefail git add . git add -A

args=("$@")

if [[ ${#args[@]} -lt 1 ]]; then args+=('squash-this-commit') fi

git commit -am "'${args[@]}'" || { echo; } git push

)}

with: git commit -am 'some stuff here', I really don't like having to enter in quotes, so I am looking to do:

ores_simple_push my git commit message here gets put into a single string

so that would become:

git commit -am 'my git commit message here gets put into a single string'

is there a sane way to do this?

2 Answers2

7

In Korn/POSIX-like shells, while "$@" expands to all the positional parameters, separated (in list contexts), "$*" expands to the concatenation of the positional parameters with the first character (byte with some shells) of $IFS¹ or with SPC if $IFS is unset or with nothing if $IFS is set to the empty string.

And in ksh/zsh/bash/yash (the Bourne-like shells with array support), that's the same for "${array[@]}" vs "${array[*]}".

In zsh, "$array" is the same as "${array[*]}" while in ksh/bash, it's the same as "${array[0]}". In yash, that's the same as "${array[@]}".

In zsh, you can join the elements of an array with arbitrary separators with the j parameter expansion flag: "${(j[ ])array}" to join on space for instance. It's not limited to single character/byte strings, you can also do "${(j[ and ])array}" for instance and use the p parameter expansion flag to be able to use escape sequences or variables in the separator specification (like "${(pj[\t])array}" to join on TABs and "${(pj[$var])array}" to join with the contents of $var). See also the F shortcut flag (same as pj[\n]) to join with line-feed.

So here:

ores_simple_push() (
  set -o errexit -o pipefail
  git add .
  git add -A

args=("$@")

if [[ ${#args[@]} -lt 1 ]]; then args+=('squash-this-commit') fi

IFS=' ' git commit -am "${args[*]}" || true git push )

Or just POSIXly:

ores_simple_push() (
  set -o errexit
  git add .
  git add -A

[ "$#" -gt 0 ] || set square-this-commit

IFS=' ' git commit -am "$*" || true git push )

With some shells (including bash, ksh93, mksh and bosh but not dash, zsh nor yash), you can also use "${*-square-this-commit}" here.

For completeness, in bash, to join arrays with arbitrary strings (for the equivalent of zsh's joined=${(ps[$sep])array}), you can do:

IFS=
joined="${array[*]/#/$sep}"
joined=${joined#"$sep"}

(that's assuming $sep is valid text in the locale; if not, there's a chance the second step fails if the contents of $sep ends up forming valid text when concatenated with the rest).


¹ As a historical note, in the Bourne shell, they were joined with SPC regardless of the value of $IFS

-1

Actually this seems to work, but I don't know why:

  git commit -am "${args}" || { echo; }