0

Running this bash script running gives two different results. Can anyone explain why? Is there a better "bash one liner" to duplicate "$@" into a new variable that then behaves to same way when iterated over in a for loop using the same loop syntax? (An array requires different syntax to loop over.)

#!/bin/bash
# run as: bash thisScript.bash "arg one" "arg two"

args="$@"

echo 'Testing @:'
for i in "$@" ; do
  echo "$i"
done

echo 'Testing args:'
for i in "$args" ; do
  echo "$i"
done

I did find the following quote, but it doesn't fully explain what's happening, and it isn't helpful in duplicating the "$@"construct:

"Assigning the arguments to a regular variable (as in args="$@") mashes all the arguments together just like "$*" does."

There seems to be something special about the "$@" construct, almost as if the resulting value that gets iterated over is a different type from other variables. Or maybe the resulting intermediary value has alternatively separated (not space separated) values or something.

In Python I could check this using type(@) or repr(@) but I haven't found a bash equivalent that preserves the internal separators of "$@" or whatever makes it behave specially when iterated over.

Perhaps it is simply not possible to duplicate the "$@" construct. If anyone knows, I would love to hear an explanation.

I'm not looking for a solution to a specific problem. (I already know how to work around problems caused by the above, although the workarounds are clumsy IMO.)

Rather I'd like to fully understand why it can't be duplicated, or what method could be used to duplicate it, which could help me better understand how bash works.

I could go digging through the bash source code, but I'd prefer not to have to, as that would be quite the rabbit hole to go down.

Thanks for any feedback. :)

  • Anothertread has this answered but hadn't been easy to find, supposedly, inside another function, positional parameters can be restored using: set "${args[@]}"; – joetainment Dec 03 '20 at 10:44
  • `There seems to be something special about the "$@" construct` Yes, it's super special. See [bash manual special parameters](https://www.gnu.org/software/bash/manual/bash.html#Special-Parameters) and just [posix manual special parameters](https://pubs.opengroup.org/onlinepubs/009604499/utilities/xcu_chap02.html#tag_02_05_02). `why it can't be duplicated` It _can_, but in POSIX shell it requires additional work with `printf "%q"` and `eval`. But in bash, just use arrays. Anyway, read about [word splitting](https://www.gnu.org/software/bash/manual/bash.html#Word-Splitting) and bash arrays. – KamilCuk Dec 03 '20 at 10:46
  • You are searching for just `args=("$@"); for i in "${args[@]}"` ... – KamilCuk Dec 03 '20 at 10:47
  • @KamilCuk Thanks for the links about the specs! – joetainment Dec 03 '20 at 11:11
  • @KamilCuk Your array suggestion didn't work for me , since that involves different syntax in the foo-loop which I was explicitly trying to avoid. It turns out the simplest and closest approxmation for my case is using: set -- "${args[@]}" inside a function after I've captured the args as an array. Then the same syntax can be used in the for loop, and code that previously worked outside of functions referencing the original positional parameters will then work in the function! – joetainment Dec 03 '20 at 11:12
  • `didn't work for me , since that involves different syntax in the foo-loop which I was explicitly trying to avoid` I do not understand. Why are you trying to avoid? So there is a solution to your problem, but you do not want to use it. Why? Yes, you can reinitialize positional arguments. – KamilCuk Dec 03 '20 at 11:12
  • @KamilCuk If you have a link to any info on your statement "it requires additional work with printf "%q" and eval" I'd love to know more. I actually tried that but couldn't get it working yet. – joetainment Dec 03 '20 at 11:13
  • What for? Use bash arrays. It would be `args="$(printf "%q " "$@")"` followed by `eval "set -- $args"; for i in "$@"`. – KamilCuk Dec 03 '20 at 11:14
  • 1
    @KamilCuk "I do not understand. Why are you trying to avoid? So there is a solution to your problem, but you do not want to use it. Why?" Curiosity mostly, I am just trying to gain a deeper understanding into how it works. Your links and suggestions have already been helpful, so thanks again. Your last suggestion was especially educational! – joetainment Dec 03 '20 at 11:19
  • If so, I also recommend [posix shell C.2.5 Parameters and Variables](https://pubs.opengroup.org/onlinepubs/9699919799/xrat/V4_xcu_chap02.html#tag_23_02_05) - it's full of examples of how `$*` `$@` work in different contexts in corner cases. (I believe formatting there is wrong and some newlines are missing, but anyway) – KamilCuk Dec 03 '20 at 11:39

0 Answers0