0

I'm experimenting a little bit with a shell script, which should run git commands for multiple repositories on the same level. This project structure might be a bad idea, but this is another story.

Everything works fine until I've run into this problem:

DETAIL="test test" && command="commit -m '${DETAIL}'" && echo $(git ${command})
# -> error: pathspec 'test'' did not match any file(s) known to git.

I've also tried other opportunities like

DETAIL="test test" && command="commit -m ${DETAIL}" && echo $(git ${command})
DETAIL="test test" && command="commit -m $DETAIL" && echo $(git ${command})

All give the same result (see above). I've also scanned these docs about string expansion, but I don't have the problem, that the variables/strings might be null or undefined. The last echo is not the problem, you can also store the result of $(git status) in a variable and echo this one (my way in the script).

I know, there are similar questions, but I did not found a similar scenario yet, since I'm just dealing with simple and non-null strings, but with (too?) many quotes.

Interesting variant:

DETAIL="test test" && command="commit -m '${DETAIL}'" && echo $("git ${command}")
# -> git commit -m 'test test': command not found # WHAT?

Also interesting, just:

command="commit -m 'test'" && echo $(git ${command})

works fine.

1 Answer 1

2

Use bash arrays with proper quoting...

DETAIL="test test" && command=(commit -m "$DETAIL") && git "${command[@]}"

To your code:

  • echo "$(command)" is the same as command (ok, trailing empty newlines are removed)
  • "command blabla" does not execute file command with the first argument blabla. It will execute a filename named exactly with space command blabla.
  • Inside $("git ${command}") you want to execute a filename named git commit -m 'test test' (exactly, this is the whole filename name, with spaces, after ${command} is expanded). As on you system there is no file named git commit -m 'test test' bash returns command not found.
Sign up to request clarification or add additional context in comments.

3 Comments

Great, thanks. Now I'm struggling with pouring this array into a local function and getting it right there. Here runCommand is my local function: declare -a commandArray=("commit" "-m" "${DETAIL}"); - next line - run_command $commandArray. Then inside the function: local actualCommand=$@ - then - result=$(git ${actualCommand[@]})?
bash doesn't have first-class array values. When you say something is an array, it just means that there is an attribute set on the name which allows you to using indexing. It's really a thin layer of syntactic sugar over a set of distinct variables.
If arr=(1 "2 3" 4), then: f "${arr[@]}" is equal to f 1 "2 3" 4. But f ${arr[@]} is equal to f 1 2 3 4, ie. the " matter. Only "${arr[@]}" will be properly exapanded. Using $arr you will get only first element. You can inside a function local actualCommand=("$@").

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.