我在嵌套文件结构中有大约15000个图像,其名称为SKUS。我需要确保没有相同SKU的文件实际上是不同的文件。
例如,如果我有两个或多个名为MYSKU.jpg
的文件,我需要确保它们之间没有任何不同。
在bash命令中执行此操作的最佳方式是什么?
答案 0 :(得分:3)
我不想完全为你解决任务,但这里有一些你可以尝试和整合的有用成分:
find /path -type f # gives you a list of all files in /path
您可以像这样遍历列表
for f in $(find /path -type f -name '*.jpg'); do
...
done
现在你可以想到你需要在循环中收集的东西。我建议
base=$(basename $f)
full_path=$f
hash=$(echo $f | md5sum | awk '{print $1}')
现在,您可以将此信息存储在文件的三列中,以便每行包含您需要了解的有关文件的所有内容以查找重复项。
因为你没有解释你需要如何处理重复项,所以这里只是一个如何发现它们的建议。然后由你决定如何处理它们。
根据我们上面获得的列表,你可以存储它的两个副本:一个是按basename排序,另一个是按basename 排序,不包括重复:
sort -k2 list.txt | column -t > list.sorted.txt
sort -k2 -u list.txt | column -t > list.sorted.uniq.txt
这里我假设基本名称在第二列
现在运行
diff list.sorted.txt list.sorted.uniq.txt
查看具有相同名称的文件。现在,您可以从每一行中提取MD5校验和,以验证它们是否真的不同,也是完整路径,以便执行mv
,rm
,ln
等行为。< / p>
答案 1 :(得分:1)
我们的想法是扫描所有文件的目录,并根据md5校验和检查哪个文件名相同但内容不同
#!/bin/bash
# directory to scan
scan_dir=$1
[ ! -d "$1" ] && echo "Usage $0 <scan dir>" && exit 1
# Associative array to save hash table
declare -A HASH_TABLE
# Associative array of full path of items
declare -A FULL_PATH
for item in $( find $scan_dir -type f ) ; do
file=$(basename $item)
md5=$(md5sum $item | cut -f1 -d\ )
if [ -z "${HASH_TABLE[$file]}" ] ; then
HASH_TABLE[$file]=$md5
FULL_PATH[$file]=$item
else
if [ "${HASH_TABLE[$file]}" != "$md5" ] ; then
echo "differ $item from ${FULL_PATH[$file]}"
fi
fi
done
用法(假设您将脚本文件命名为scan_dir.sh
:
$ ./scan_dir.sh /path/to/you/directory
答案 2 :(得分:0)
以下是我将如何用bash 4解决它:
#!/usr/local/bin/bash -vx
#!/usr/local/bin/bash -vx
shopt -s globstar # turn on recursive globbing
shopt -s nullglob # hide globs that don't match anything
shopt -s nocaseglob # match globs regardless of capitalization
images=( **/*.{gif,jpeg,jpg,png} ) # all the image files
declare -A homonyms # associative array of like named files
for i in "${!images[@]}"; do # iterate over indices
base=${images[i]##*/} # file name without path
homonyms["$base"]+="$i " # Space delimited list of indices for this basename
done
for base in "${!homonyms[@]}"; do # distinct basenames
unset dupehashes; declare -A dupehashes # temporary var for hashes
indices=( ${homonyms["$base"]} ) # omit quotes to allow expansion of space-delimited integers
(( ${#indices[@]} > 1 )) || continue # ignore unique names
for i in "${indices[@]}"; do
dupehashes[$(md5 < "${images[i]}")]+="$i "
done
(( ${#dupehashes[@]} > 1 )) || continue # ignore if same hash
echo
printf 'The following files have different hashes: '
for h in "${!dupehashes[@]}"; do
for i in ${dupehashes[$h]}; do # omit quotes to expand space-delimited integer list
printf '%s %s\n' "$h" "${images[i]}"
done
done
done
我知道上面的内容看起来很多,但我认为使用15k图像你真的想避免open()
和校验和你不需要的那些,所以这种方法被调整为将数据集缩小到重复文件名,然后只对内容进行哈希处理。正如其他人之前所说的那样,你可以通过在散列之前检查文件大小来更快地实现这一点,但是我会让那部分未完成。