1 背景
大家很习惯的使用cp命令和mv命令配合通配符*来实现特定目的,如期望拷贝或移动特定目录下的所有文件:
cp foo/* bar/
mv foo/* bar/如果我们有封装此类函数的需要,则需要写一个函数:
function copyTo () {
source_path=$1
target_path=$2
cp $source_path $target_path
if (( $? != 0 )); then
echo "error!"
exit 1
fi
}此时我们期望将目录foo下的所有文件

拷贝到目录bar里,于是我们尝试调用它:
copyTo foo/* bar然后我们可能会得到一堆奇奇怪怪的东西,就比如aaa和bbb文件完全一样了!

这种写法是错误的。
2 原理
假设我们写一个函数:
function test (){
echo $@
}然后同样尝试调用:
test foo/* bar我们可能会很惊讶的发现它的输出是:
foo/aaa foo/bbb bar
也就是说,shell 将路径通配符展开成多个参数,然后传递给test函数,然而我们的目的是将foo/aaa和foo/bbb拷贝到bar目录。
3 解决方案
我们可以利用${!#}获取最后一个参数,通过for遍历${@:1:$# - 1}来获取除最后一个以外的所有元素。最终得到的函数如下:
function copyTo () {
target_path=${!#}
for source_path in "${@:1:$# - 1}"
do
echo "copy" $source_path "->" $target_path
cp $source_path $target_path
if (( $? != 0 )); then
echo "error!"
exit 1
fi
done
}我们执行一下copyTo foo/* bar得到

完成!