Reputation: 91630
Currently at work on the following version of Bash:
GNU bash, version 4.2.46(1)-release (x86_64-redhat-linux-gnu)
My current script:
#!/usr/bin/env bash
function main() {
local commands=$@
for command in ${commands[@]} ; do
echo "command arg: $command"
done
}
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
set -e
main $@
fi
In simple terms, this script will only exec main
if it's the script being called, similar to Python's if __name__ == '__main__'
convention.
In the main
function, I'm simply looping over all the command variables, but quote escaping isn't happening as expected:
$ tests/simple /bin/bash -c 'echo true'
command arg: /bin/bash
command arg: -c
command arg: echo
command arg: true
The last argument here should get parsed by Bash as a single argument, nevertheless it is split into individual words.
What am I doing wrong? I want echo true
to show up as a single argument.
Upvotes: 1
Views: 252
Reputation: 930
Quoting of @ passed to main was your issue, but I thought I would mention that you also do not need to assign the value inside main to use it. You could do the following:
main()
{
for command
do
...
done
}
main "$@"
Upvotes: 0
Reputation: 42999
You are getting the right output except for the 'echo true'
part which is getting word split. You need to use double quotes in your code:
main "$@"
And in the function:
function main() {
local commands=("$@") # need () and double quotes here
for command in "${commands[@]}" ; do
echo "command arg: $command"
done
}
The function gets its own copy of $@
and hence you don't really need to make a local copy of it.
With these changes, we get this output:
command arg: /bin/bash
command arg: -c
command arg: echo true
In general, it is not good to store shell commands in a variable. See BashFAQ/050.
See also:
Upvotes: 2
Reputation: 47169
You'll likely want to do something more like this:
function main() {
while [ $# -gt 0 ]
do
echo "$1"
shift
done
}
main /bin/bash -c "echo true"
The key really being $#
, which counts the number of command line arguments, (not including the invocation name $0
). The environment variable $#
is automatically set to the number of command line arguments. If the function/script was called with the following command line:
$ main /bin/bash -c "echo true"
$#
would have the value "3" for the arguments: "/bin/bash", "-c", and "echo true". The last one counts as one argument, because they are enclosed within quotes.
shift
command "shifts" all command line arguments one position to the left. main
). Upvotes: 0