Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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(){
   clear
    src=$1
    dst=$2
    typ=$3
    if [ ! -d $dst ]
      then
        mkdir $dst
      fi

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


  }
share|improve this question

migrated from serverfault.com Oct 2 '12 at 15:23

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

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

1 Answer

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 () {
  src="$1"
  dst="$2"
  shift 2
  typ=("$@")
  …
}

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(){
  src="$1"
  dst="$2"
  typ=("$@")
  if [ ! -d "$dst" ];  then mkdir -- "$dst"; fi
  for i in "${typ[@]}"; do
    find "$src" -name "${i}" -exec mv {} "${dst}" \;
  done
}

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
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.