Bash ignores Quotes in command line arguments [duplicate] - bash

This question already has answers here:
When to wrap quotes around a shell variable?
(5 answers)
How to keep quotes in Bash arguments? [duplicate]
(14 answers)
Closed 2 years ago.
Got some odd behaviour coming out of a bash script
myscript.sh
#! /bin/bash
# Demo bash script
for i in $#
do
echo $i
done
echo $# args
if I execute it thus:
myscript.sh "Arg 1" "Arg 2"
Result:
Arg
1
Arg
2
2 args
So it's calculating the correct number of args but processing them wrong or more to the point I'm processing them wrong
Any thoughts?

Change
for i in $#
to
for i in "$#"
in order to apply correctly parameter expansion.

Related

How to execute a command that is the arguments to the script? [duplicate]

This question already has answers here:
What is the difference between $* and $#
(4 answers)
How do I pass on script arguments that contain quotes/spaces?
(2 answers)
Closed last month.
I want a bash script, call it args, to execute a command that is the arguments to the script.
In particular, I would like this command (note multiple blanks):
$./args echo 'foobar *0x0'
to execute this precise command:
echo 'foobar *0x0'
I tried this in args:
#!/bin/bash
set -x
$*
but it doesn't work:
./args echo 'foobar *0x0'
+ echo foobar '*0x0'
foobar *0x0
Witness the single space, as well as moved single quotes.
With $#, the result is exactly the same, so please don't close the question on the account of differences between $* and $#. Also, blanks are not my only problem, there is the *0x0.
#!/bin/bash
"$#"
This expands to all of the command-line arguments with spacing and quoting intact. $*, by contrast, is subject to unwanted word splitting and globbing since it's not quoted.

quotation marks in bash script around $#? [duplicate]

This question already has answers here:
Parsing/passing command line arguments to a bash script - what is the difference between "$#" and "$*"?
(3 answers)
When to wrap quotes around a shell variable?
(5 answers)
How to preserve double quotes in $# in a shell script?
(6 answers)
Closed 5 years ago.
I found the following snippet of bash script from How can I run a function from a script in command line?
$ cat test.sh
testA() {
echo "TEST A $1";
}
testB() {
echo "TEST B $2";
}
"$#"
This works well.
One of the response of this answer is Use "$#" in most cases. $# is not safe in some cases
I'm wondering why $# needs quotation marks, "$#" , in the last line.
What makes it difference with or without quotation marks around $# in the bash script?
"$#" quotes each positional paremeter that is expanded. For example:
# script.sh
cat "$#"
cat $#
If you do script "a b" the first cat will try to emit a file literally named a b. Since the positional parameters aren't quoted for the second cat, it will try to emit individual files named a and b. This can cause all kinds of problems since the user quoted the value passed to script and expected it to be handled as one word/unit.
Note that "$#" is a bit special since if you do script "a b" "c d" this expands to: cat "a b" "c d" in the script rather than cat "a b c d". The second line would do cat a b c d which tries to concatenate four different files rather than two files with spaces in the name.

Meaning of # in bash scripts [duplicate]

This question already has answers here:
What does $# mean in a shell script?
(8 answers)
Closed 5 years ago.
What's is the meaning of # in the following code excerpt from mariadb docker image entrypoint
...
SOCKET="$(_get_config 'socket' "$#")"
"$#" --skip-networking --socket="${SOCKET}" &
pid="$!"
mysql=( mysql --protocol=socket -uroot -hlocalhost --socket="${SOCKET}" )
for i in {30..0}; do
if echo 'SELECT 1' | "${mysql[#]}" &> /dev/null; then
break
...
Would be happy to get a reference to good manual/reference to bash, as searching in google for # meaning in bash couldn't produce good results.
The GNU man bash page would be a good place to start
#
($#) Expands to the positional parameters, starting from one. When the expansion occurs within double quotes, each parameter expands to a separate word. That is, "$#" is equivalent to "$1" "$2" …. If the double-quoted expansion occurs within a word, the expansion of the first parameter is joined with the beginning part of the original word, and the expansion of the last parameter is joined with the last part of the original word. When there are no positional parameters, "$#" and $# expand to nothing (i.e., they are removed).
A small example to demonstrate the same,
function foo() {
printf "%s\n" "$#"
}
foo 1 2 3
would print
1
2
3

Error "command not found" when setting value to variable [duplicate]

This question already has answers here:
Indirect variable assignment in bash
(7 answers)
What is indirect expansion? What does ${!var*} mean?
(6 answers)
Closed 6 years ago.
I have the following test.sh script:
#!/bin/bash
foo=0
bar=foo;
${bar}=1
echo $foo;
Output:
./test.sh: line 4: foo=1: command not found
0
Why the "command not found" error? How to change script to "echo $foo" outputs 1?
That's not the way to do indirection unfortunately. To do what you want you could use printf like so
printf -v "$bar" "1"
which will store the value printed (here 1 in the variable name given as an argument to -v which when $bar expands here will be foo
Also, you could use declare like
declare "$bar"=1
which will do variable substitution before executing the declare command.
In your attempt the order of bash processing is biting you. Before variable expansion is done the line is split into commands. A command can include variable assignments, however, at that point you do not have a variable assignment of the form name=value so that part of the command is not treated as an assignment. After that, variable expansion is done and it becomes foo=1 but by then we're done deciding if it's an assignment or not, so just because it now looks like one doesn't mean it gets treated as such.
Since it was not processed as a variable assignment, it must not be treated as a command. You don't have a command named foo=1 in your path, so you get the error of command not found.
You need to use the eval function, like
#!/bin/bash
foo=0
bar=foo;
eval "${bar}=1"
echo $foo;
The ${bar}=1 will first go through the substitution process so it becomes foo=1, and then the eval will evaluate that in context of your shell

How to pass quoted arguments from variable to bash script [duplicate]

This question already has answers here:
Why does shell ignore quoting characters in arguments passed to it through variables? [duplicate]
(3 answers)
Closed 2 years ago.
I tried building a set of arguments in a variable and passing that to a script but the behavior different from what I expected.
test.sh
#!/bin/bash
for var in "$#"; do
echo "$var"
done
input
usr#host$ ARGS="-a \"arg one\" -b \"arg two\""
usr#host$ ./test.sh $ARGS
output
-a
"arg
one"
-b
"arg
two"
expected
-a
arg one
-b
arg two
Note if you pass the quoted arguments directly to the script it works. I also can work around this with eval but I wanted to understand why the first approach failed.
workaround
ARGS="./test.sh -a "arg one" -b "arg two""
eval $ARGS
You should use an array, which in some sense provides a 2nd level of quoting:
ARGS=(-a "arg one" -b "arg two")
./test.sh "${ARGS[#]}"
The array expansion produces one word per element of the array, so that the whitespace you quoted when the array was created is not treated as a word separator when constructing the list of arguments that are passed to test.sh.
Note that arrays are not supported by the POSIX shell, but this is the precise shortcoming in the POSIX shell that arrays were introduced to correct.

Resources