我正在编写脚本以满足我自己的需求,在 bash 中对我的 Mac 上的下载文件夹进行排序。我传递给函数的参数是:源目录、目标目录和我想要移动的文件扩展名数组。我的问题是,当函数位于“find”行时,它只会复制一个具有该扩展名的文件,但是当我删除所有变量并直接输入参数时,它就可以正常工作。发生了什么?
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
}
答案1
函数的每个参数都是标量,而你试图传递一个数组。当你写
a=(foo bar qux)
moveFaster "$src" "$dst" "${a[@]}"
然后 moveFaster 接收五个参数:$src
、$dst
、foo
和。如果你写bar
,那么只有数组的第一个元素被传递给函数,因为它本身扩展为数组的第一个元素。此外,你对 的赋值使它成为一个标量变量。qux
moveFaster "$src" "$dst" "$a"
$a
typ
由于您要将单个数组传递给函数,因此您可以声明它由所有剩余的参数组成。
moveFaster () {
src="$1"
dst="$2"
shift 2
typ=("$@")
…
}
与此相关的是,如果涉及的任何文件名包含空格或通配符 ( ?*\[
),您的脚本将失败。为了避免这种情况,请遵守以下简单的 shell 编程规则:总是用双引号括住变量替换(除非您理解为什么在特定情况下它们不能出现)。
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
}
另外,如果您使用的是 bash 4 或更高版本,那么仅使用 bash 功能就可以相当轻松地完成此操作。该extglob
选项允许扩展 glob 模式,例如@(PATTERN1|PATTERN2)
。该globstar
选项允许递归匹配子目录中**/PATTERN
名称匹配的文件。PATTERN
shopt -s extglob globstar
mkdir -p /common/destination/directory
mv /path/to/source/**/@(*.txt|*.html|README) /common/destination/directory