我需要创建一个目录树的克隆,以便我可以清理重复的文件。
我不需要文件的副本,我只需要文件,所以我想创建一个带有硬链接的匹配树。
当我意识到我的备份需要数小时时,我在几分钟内把它扔在一起
它只是回显我在运行之前重定向到文件中检查的命令。
当然,通常的问题,比如包含引号或逗号的文件和目录都没有得到解决(bash脚本很糟糕,没有它,这个和包含前导破折号的文件)
是否有一些实用工具已经以稳健的方式实现了这一目标?
BASEDIR=$1
DESTDIR=$2
for DIR in `find "$BASEDIR" -type d`
do
RELPATH=`echo $DIR | sed "s,$BASEDIR,,"`
DESTPATH=${DESTDIR}/$RELPATH
echo mkdir -p \"$DESTPATH\"
done
for FILE in `find "$BASEDIR" -type f`
do
RELPATH=`echo $FILE | sed "s,$BASEDIR,,"`
DESTPATH=${DESTDIR}/$RELPATH
echo ln \"$FILE\" \"$DESTPATH\"
done
答案 0 :(得分:1)
通常使用find这样做是个坏主意 - 你基本上依赖于在空格上分隔文件名,而实际上所有形式的空格在大多数UNIX系统上都是有效的文件名。查找本身能够在找到的每个文件上运行单个命令,这通常是更好的选择。我建议做这样的事情(我为了简单起见使用了几个脚本,不知道在一个中完成这一切是多么容易):
main.sh:
BASEDIR="$1" #I tend to quote all variables - good habit to avoid problems with spaces, etc.
DESTDIR="$2"
find "$BASEDIR" -type d -exec ./handle_file.sh \{\} "$BASEDIR" "$DESTDIR" \; # \{\} is replaced with the filename, \; tells find the command is over
find "$BASEDIR" -type f -exec ./handle_file.sh \{\} "$BASEDIR" "$DESTDIR" \;
handle_file.sh:
FILENAME="$1"
BASEDIR="$2"
DESTDIR="$3"
RELPATH="${FILENAME#"$BASEDIR"}" # bash string substitution double quoting, to stop BASEDIR being interpreted as a pattern
DESTPATH="${DESTDIR}/$RELPATH"
if [ -f "$FILENAME" ]; then
echo ln \""$FILENAME"\" \""$DESTPATH"\"
elif [ -d "$FILENAME" ]; then
echo mkdir -p \""$DESTPATH"\"
fi
我用一个简单的树来测试它,包括空格,星号,撇号,甚至是文件名中的回车,它似乎都有效。
显然删除了转义的引号和" echo" (但保留真实的引号)以使其适用于真实。