LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - General (https://www.linuxquestions.org/questions/linux-general-1/)
-   -   Bash Arguments Problem (https://www.linuxquestions.org/questions/linux-general-1/bash-arguments-problem-4175736500/)

Linunix 04-28-2024 12:09 AM

Bash Arguments Problem
 
Hello
Encountered a problem concerning script arguments in bash (likely also sh). Arguments to a call of a script get unboxed in the sense that surrounding quotation characters '"' are removed in the values you can use inside of the script, namely as $1, $2 $* etc. These quotations are used e.g. when an argument contains blank characters. So far so good, but if you need to pass some or all script arguments on to some other program call inside the script, what will you do?

If you don't know the exact number of arguments, you would be inclined to use "$*" as single argument to Z (your inside program call). But this loses the brackets '"' and the call fails due to incorrect argument transmission. You can use "$1" "$2" "$3" etc. as arguments to Z but this fixes the number of arguments, which is not always a tolerable error.

What is in demand is a way to transmit the original arguments to a script on to a subprogram. I have not found such a way. Anybody has a solution?

astrogeek 04-28-2024 01:24 AM

That is what "$@" is for. From man bash:

Code:

@    Expands to the positional parameters, starting from one.  In contexts where word  splitting
      is performed, this expands each positional parameter to a separate word; if not within dou‐
      ble quotes, these words are subject to word splitting.  In contexts where word splitting is
      not  performed, this expands to a single word with each positional parameter separated by a
      space.  When the expansion occurs within double quotes, each parameter expands to  a  sepa‐
      rate  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).


Linunix 04-28-2024 02:28 AM

Thanks!
I read that before but I wonder if it's implemented because it can't produce any difference to "$*" with "$@" or ""$@"".
For instance I tried
Code:

echo "cmdline \$@ = "$@""
echo "$@" > clfile
cat clfile

but I don't receive any quoted arguments.

lvm_ 04-28-2024 11:51 AM

You shouldn't, quotes are means to alter processing of certain characters, not argument delimiters. The difference between "$@" and "$*" is noticeable only when passing arguments to a function or process.

astrogeek 04-28-2024 01:59 PM

Quote:

Originally Posted by Linunix (Post 6498655)
Thanks!
I read that before but I wonder if it's implemented because it can't produce any difference to "$*" with "$@" or ""$@"".
For instance I tried
Code:

echo "cmdline \$@ = "$@""
echo "$@" > clfile
cat clfile

but I don't receive any quoted arguments.

Ah, I think I understand better what you are trying to do now.

The quotes themselves have meaning only for the shell which encounters them (i.e. the shell that invokes the first script), and as already pointed out, should not be thought of as delimiters so much as an escaping mechanism. Again, from man bash:

Code:

QUOTING
      Quoting  is  used to remove the special meaning of certain characters or words to
      the shell.
        ...
      There are three quoting mechanisms: the escape character, single quotes, and dou‐
      ble quotes.

So the first application never sees the quotes themselves (their special meaning was for the invoking shell), the target script only receives the (previously escaped) values. When you then pass those values on within your script such as via "$@", you pass on the received meaning of those parameters, but not any escaping mechanism used to allow you to receive them. If the original parameter was empty (i.e. nothing ordinary and nothing escaped) then you pass on that same nothing to the next application. The quotes in "$@" again have meaning to the current shell, not the shell in which the constructed command is executed, and not to the target script.

If for some reason you really needed to pass something instead of nothing for those received empty parameters, it would be up to your first application to escape the nothings it had received into something that can be passed along to the next application, perhaps by finding the empty ones and replacing them with a set of escaped quotes, \"\". Then the current shell would ignore the special meaning of quotes, the shell in which the next command is executed would see the empty quotes as an escaped nothing and pass along an empty parameter, and the target script would receive the meaning of an empty positional parameter.

Hope that makes sense!

pan64 04-29-2024 01:58 AM

the quotes are not part of the argument itself, they are just part of the command line.
bash (or sh, zsh) will evaluate the text you entered. The string between " " will be kept together, it will be a single argument, but without " it will be split by whitespaces.
' and " works differently, would be nice to check the documentation about quotation.
If you want to inspect the current arguments you can use something like this:
Code:

for i in "$@"
do
    ((++j)
    echo "${j}:${i}<<<" # this is to see the end of the value
done

you can use $* instead of $@ and you will see the difference
you can check this page too: https://tldp.org/LDP/abs/html/
also I recommend shellcheck to make your script even better

MadeInGermany 04-30-2024 12:35 PM

echo prints a space between its arguments, not good for distinguishing them from embedded space characters.
Yes a for loop can do it, or printf:
Code:

printf "%s\n" "$@"
Code:

printf '"%s" ' "$@"
Unlike the * (that concatenates to a string), the @ keeps the individuals. The same is for arrays:
Code:

arr=( "$@" )
printf "%s\n" "${arr[@]}"

Change any of the @ to * and it "spoils" to a string (not revertible - information is lost).


All times are GMT -5. The time now is 01:42 PM.