1

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?

0

3 Answers 3

5

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.

Sign up to request clarification or add additional context in comments.

4 Comments

Of course, you could grab the last element then unset it, which is basically the same as shifting off the end.
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.)
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?
Correcting and simplifying my previous comment: ${@:1:$#-1}
3

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 $@).

Comments

2

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

You can consider use getopts command for parameter parsing.

Best regards

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.