tags:

views:

48

answers:

3

I have a bash function (slightly simplified for explaining)

copy_to() {
    cp $1 $2 $3
}

This works fine:

copy_to -f /demo/example1.xml new_demo/

But Let's say I want to copy all the xml files, the following code will have issues:

copy_to -f /demo/*.xml new_demo/

Obviously I could just write cp -f /demo/*.xml new_demo/, but is there anyway to get the copy_to function to work for a list of files (which passes more than just 3 parameters) as well as a single file?

+1  A: 

There are $@ and $* which contain a list of all parameters. You should use $@, because it works inside of double quotes. Else, file names containing spaces would break your code.

copy_to() {
    cp "$@"
}

If one of the parameters is special, you can use the shift command to remove it from the list of parameters, like so:

example() {
    destination="$1"
    shift
    echo "copying $@ to $destination"
}

shift removes the first parameter from the list, therefore you’ll have to save it in another location first. After calling shift, the contents of $1 will be what was $2, $2 will contain what was $3 and so on. $@ expands to all parameters (excluding those that were removed by shift).

Note that you cannot shift parameters off the end of your parameter list, only from the beginning.

Scytale
Of course, you could grab the last element then unset it, which is basically the same as shifting off the end.
Jefromi
Although doing that is quite a bit more complicated. How would you do it? Is there even a POSIX-compatible way to do it? (Yes, I know the question says “bash”, but most people don’t know the difference, and writing for a single shell only is bad.)
Scytale
In Bash, you can access all but the last parameter like this: `${@:0:$((${#@} - 1))}` (subtract 2 to omit the last two, etc.). Writing for a single shell only is not always bad - why have other shells if all you're going to use is the POSIX (or original Bourne) subset?
Dennis Williamson
A: 

As Scytale said $0 and $* contain a list of all parameters. $# contains param count.

You can consider use getopts command for parameter parsing.

Best regards

SourceRebels
I think you mean `$@`, not `$0`, which contains the name of the script as it was run, i.e. like `argv[0]`.
Jefromi
+1  A: 

If you need to iterate over the arguments:

f() {
    for arg
    do
        do_something $arg
    done
}

The in $@ is implied in for arg (explicitly: for arg in $@).

Dennis Williamson