7

There is an existing bash script I need to modify, but I want to encapsulate the changes required to it in a function without affect how it manipulates the '$@' variable.

My idea is to copy the argument string to a new variable and extract the arguments required separately, but it seems that applying the 'shift' operates only on the $@ variable and modifies it permanently.

Is there way to emulate the processing of the $@ variable and its related functions on a normal string?

vfclists
  • 19,193
  • 21
  • 73
  • 92

2 Answers2

12

You can preserve the $@ into a BASH array:

args=("$@")

And construct/retrieve/process original arguments anytime from BASH array "${args[@]}"

John Kugelman
  • 349,597
  • 67
  • 533
  • 578
anubhava
  • 761,203
  • 64
  • 569
  • 643
  • 1
    Is it possible to restore the ${args[@]} back to $@?, ie after saving $@ to args I can execute $@=args and allow the original parts of the script to run unmodified, rather than replace the @ in the original parts of the script with {args[0]} or any other variable it was initially saved to? – vfclists Mar 01 '14 at 18:09
  • 3
    Yes sure you can just do: `set "${args[@]}";` to reconstruct original argument list again. – anubhava Mar 01 '14 at 18:15
  • 11
    Use `set -- "${args[@]}"`, or you risk an optional argument being mistaken as one of the shell options that `set` can set. – chepner Mar 01 '14 at 22:46
0

Your question is a bit vage, there is no code shown. So I just guess this may help:

#!/bin/bash
atline=$@

echo ---------- complete command line:
echo $atline
echo ---------- dissecting command line syntax 1
for e in $atline; do echo $e; done
echo ---------- syntax 2
for ee ; do echo $ee; done

The result of one run is:

strobel@suse131:~/bin> test.sh one two three "four and five"
---------- complete command line:
one two three four and five
---------- dissecting command line syntax 1
one
two
three
four
and
five
---------- syntax 2
one
two
three
four and five

As you see, one problem is parsing of arguments that contain spaces. One reason to never put spaces into file names.

Another possible solution:

the bash reference says The positional parameters are temporarily replaced when a shell function is executed so you could isolate your code in a function.

I think shift should not be used in bash scripts, there are better solutions as you can see.

Str.
  • 1,389
  • 9
  • 14
  • `atline=$@` is inherently buggy: It's stuffing an **array** into a **string**. Strings can't store everything arrays can. – Charles Duffy Mar 22 '17 at 16:51
  • 1
    ...that's not a reason to restrict your data's input domain, though -- it's a reason to store content using datatypes that can actually represent that content accurately. `atline=( "$@" )` and then `for ee in "${atline[@]}"; do echo "$ee"; done` would work perfectly. – Charles Duffy Mar 22 '17 at 16:59
  • 1
    (Also, saying that "there are better solutions as you can see" in an argument against using `shift` is a bit... bizarre... given as you haven't actually demonstrated any such better solution here -- indeed, you've demonstrated quite clearly why a given alternate approach is *faulty*). – Charles Duffy Mar 22 '17 at 17:00
  • @CharlesDuffy And how - do you think - command line arguments will become an array? – Str. Mar 23 '17 at 18:53
  • 1
    What, exactly, do you mean? `"$@"` is an array already; it's only when you try to assign that array's contents to a string that it loses its array-ness. This is why I demonstrated, above, assigning to an array (with `atline=( "$@" )`), thus preserving the original value in full. – Charles Duffy Mar 23 '17 at 19:48
  • Run `set -- "first argument" "second argument"; astring="$@"; anarray=( "$@" )`, and then compare the output of `declare -p astring` to the output of `declare -p anarray`. You'll note, among other pertinent differences, that the string uses `declare --` whereas the array uses `declare -a`; the `a` in that context indicates, well, array-ness. – Charles Duffy Mar 23 '17 at 19:50