我正在写一个bash脚本这会将文件/目录从现有目录路径移动到另一个目录路径。但在使用for loop
withif condition
语句时我无法跳过一些扩展文件。我的脚本运行时没有错误,但它不会跳过我在其中指定的所需扩展文件,if condition
而是移动所有文件和目录。下面是我尝试为其创建的脚本。
请指导我哪里做错了。
以下是我正在尝试做的事情。
#!/bin/env bash
#moving home profile data to another location
echo "Moving Desktop Files"
path=/home/$USER/Desktop/*
for m in $path
do
link=$(basename -s .lnk ${m})
desktop=$(basename -s .desktop ${m})
if [[ "${link}.lnk" == "${m}" ]] || [[ "${desktop}.desktop" == "${m}" ]]
then
echo "skipping link and desktop extension files"
continue
fi
mv -n "$m" /home/$USER/CoreData/HOME/Desktop/
done
答案1
您以一种非常迂回的方式匹配文件名后缀,并且您编写循环的方式使其无法处理名称中带有空格的文件。
与您的语句相关的主要问题if
是$m
是 路径名,包含目录路径元素,而$desktop
和$link
,如果解释为文件名,则没有目录路径元素。
更安全代码的建议:
#!/bin/bash
for name in "$HOME/Desktop"/*; do
if [[ $name == *.lnk ]] || [[ $name == *.desktop ]]; then
printf 'Skipping "%s"\n' "$name"
else
mv -n -- "$name" "$HOME/CoreData/HOME/Desktop"
fi
done
这使用与in==
内的(通配)模式匹配。[[ ... ]]
bash
如果您确实想单独进行名称通配并将它们保存在变量中,请使用数组:
names=( "$HOME/Desktop"/* )
for name in "${names[@]}"; do ... done
请注意,上面的引用对于保持各个路径名的完整性很重要。
或者,使用以下case ... esac
语句/bin/sh
:
#!/bin/sh
for name in "$HOME/Desktop"/*; do
case $name in
*.lnk|*.desktop)
printf 'Skipping "%s"\n' "$name"
;;
*)
mv -n -- "$name" "$HOME/CoreData/HOME/Desktop"
esac
done
同样,您想单独进行通配符吗:
set -- "$HOME/Desktop"/*
for name do ... done
这使用位置参数而不是命名数组。 shellsh
不支持命名数组。
或者,使用rsync
:
rsync --archive --verbose \
--exclude='*.lnk' \
--exclude='*.desktop' \
"$HOME/Desktop/" "$HOME/CoreData/HOME/Desktop"
(然后"$HOME/Desktop"
根据需要删除)