Super User is a question and answer site for computer enthusiasts and power users. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

I'm writing script for my own needs to sort Downloads folder on my mac in bash. I pass to the function parameters: source directory, destination directory and array of file extensions I want to move. My problem is that when function is in "find" line then it copies just one file with that extension but when I remove all variables and I put parameters directly then it works fine. What's going on ?

 function moveFaster(){
    if [ ! -d $dst ]
        mkdir $dst

    for i in "${typ[@]}"
        find $src -name "${i}" -exec mv {} ${dst} \;

share|improve this question

migrated from Oct 2 '12 at 15:23

This question came from our site for system and network administrators.

Put 'set -x' towards the top, so it will echo everything it does. – Zoredache Oct 2 '11 at 19:00

Each argument to a function is a scalar, and you're trying to pass an array. When you write

a=(foo bar qux)
moveFaster "$src" "$dst" "${a[@]}"

then moveFaster receives five arguments: $src, $dst, foo, bar and qux. If you write moveFaster "$src" "$dst" "$a" then only the first element of the array is passed to the function, because $a on its own expands to the first element of the array. Furthermore, your assignment to typ makes it a scalar variable.

Since you're passing a single array to the function, you can declare that it consists of all the remaining parameters.

moveFaster () {
  shift 2

On a related note, your script will fail spectacularly if any of the file names involved contains whitespace or globbing characters (?*\[). To avoid this, respect this simple shell programming rule: always put double quotes around variable substitutions (unless you understand why they must not be present in a particular case).

function moveFaster(){
  if [ ! -d "$dst" ];  then mkdir -- "$dst"; fi
  for i in "${typ[@]}"; do
    find "$src" -name "${i}" -exec mv {} "${dst}" \;

As an aside, you can do this reasonably easily with bash features alone, if you have bash version 4 or above. The extglob option allows extended glob patterns such as @(PATTERN1|PATTERN2). The globstar option allows **/PATTERN to match files whose name matches PATTERN in subdirectories recursively.

shopt -s extglob globstar
mkdir -p /common/destination/directory
mv /path/to/source/**/@(*.txt|*.html|README) /common/destination/directory
share|improve this answer

You must log in to answer this question.