我正在尝试编写一个将在Linux环境中运行的脚本。
.jpeg
它将在目录树中查找文件,然后将它们复制到名为 的目录中jpegs
。
我想让它向我显示重复的文件名,但只在生成的列表中列出一次重复的文件名(因此它不会显示相同的名称两次),而不是只向我显示错误。
这是我到目前为止的脚本:
#!/bin/sh
if ! mkdir jpegs 2> /dev/null
then
echo " Cannot create directory \"jpegs\" perhaps it already exists."
echo " delete the directory and try again."
exit
fi
for srcpath in $(find fs282/mirror -iname "*.jpg")
do
cp --backup $srcpath jpegs/
done
echo "List of Duplicate Files Follows"
答案1
不要循环 的输出find
。它是不优雅的(在找到所有路径名之前循环不会开始第一次迭代)并且危险(找到的路径名将在空格、制表符和换行符上分割,并且 shell 还将尝试将它们扩展为文件名通配模式)。
相反(如果存在名称冲突,这一切都假设您不想复制找到的文件):
find fs282/mirror -type f -iname '*.jpeg' -exec sh -c '
for pathname do
if [ -e "jpegs/${pathname##*/}" ]; then
printf "%s\n" "${pathname##*/}"
else
cp "$pathname" jpegs/
fi
done' sh {} + | sort -u
它用作find
内联 shell 脚本的路径名生成器。 find
会将找到的路径名传递给脚本,并且它将使用 中的每个路径名迭代这些路径名$pathname
。该脚本测试路径名的文件名部分是否存在于目录下jpegs
,如果存在,则将路径名末尾的文件名打印到标准输出。如果该文件名不存在jpegs
,则复制该文件。
参数替换${pathname##*/}
会删除从开头$pathname
到最后一个/
字符。] 的所有内容,仅保留末尾的文件名部分。
最后sort -u
将获取内联脚本打印的所有文件名,并对它们进行排序,同时删除重复项。
另一种方法:
find fs282/mirror -type f -iname '*.jpeg' \
! -exec sh -c '[ -e "jpegs/${1##*/}" ] && printf "%s\n" "${1##*/}"' sh {} ';' \
-exec cp {} jpegs ';' | sort -u
这本质上是同一件事,但表述完全不同。
它使用简短的内联 shell 脚本测试文件名是否存在于 下jpegs
,如果存在,则打印文件名(并稍后排序)并find
继续处理下一个文件。如果不存在,则复制该文件。
有关的: