如何在Linux中使用Shell脚本查找和删除重复文件
如何在Linux或者Unix中删除重复文件。
如何在Linux中使用Shell脚本查找重复文件。
使用Shell脚本列出Linux中的重复文件。
Linux通过名称和哈希值查找重复的文件。
自动重复文件删除器。
Shell脚本来删除重复的文件示例。
脚本1:使用Shell脚本查找重复文件
这可以帮助将用户确定为他/她希望删除的重复文件中的哪个文件。
例如/etc/hosts和/etc/hosts.bak是同一个文件,因此脚本将无法理解哪个文件很重要,并且可能会删除/etc/hosts并将其视为重复文件。
以下是在删除文件之前通过提示删除重复文件的示例脚本:
#!/bin/bash
# Find duplicate files using shell script
# Remove duplicate files interactively
TMP_FILE=$(mktemp /tmp/temp_file.XXX)
DUP_FILE=$(mktemp /tmp/dup_file.XXX)
function add_file() {
# Store the hash of the file if not already added
echo "" "" >> $TMP_FILE
}
function red () {
# print colored output
/bin/echo -e "\e[01;31m\e[0m" 1>&2
}
function del_file() {
# Delete the duplicate file
rm -f "" 2>/dev/null
[[ $? == 0 ]] && red "File \"\" deleted"
}
function srch_file() {
# Store the filename in this variable
local NEW=""
# Before we check hash value of file, make this variable null
local SUM="0"
# If file exists and the temporary file's size is zero
if [ -f $NEW ] && [ ! -s $TMP_FILE ];then
# Print Store the hash value of file. This value will be later stored in RET which is further used to check duplicate file
echo $(sha512sum ${NEW} | awk -F' ' '{print }')
# Exit the loop here
return
fi
# If the size of temporary file is non-zero read temporary file line by line in a loop. Each line is stored in ELEMENT variable
while read ELEMENT; do
# Get the hash value of input file
SUM=$(sha512sum ${NEW} | awk -F' ' '{print }')
# Get the hash value of file collected from temporary file
ELEMENT_SUM=$(echo $ELEMENT | awk -F' ' '{print }')
ELEMENT_FILENAME=$(echo $ELEMENT | awk -F' ' '{print }')
# if the hash value is same means we have found a duplicate file
if [ "${SUM}" == "${ELEMENT_SUM}" ];then
echo $ELEMENT_FILENAME > $DUP_FILE
return 1
else
continue
fi
done<$TMP_FILE
# If duplicate file is not found then just print the hash value of the file
echo "${SUM}"
}
function begin_search_and_deduplication {
local DIR_TO_SRCH=""
for FILE in `find ${DIR_TO_SRCH} -type f`; do
# this stores the return value from srch_file function
RET=`srch_file ${FILE}`
if [[ "${RET}" == "" ]];then
FILE1=`cat $DUP_FILE`
echo "$FILE1 is a duplicate of $FILE"
while true; do
read -rp "Which file you wish to delete? $FILE1 (or) $FILE: " ANS
if [ $ANS == "$FILE1" ];then
del_file $FILE1
break
elif [ $ANS == "$FILE" ];then
del_file $FILE
break
fi
done
continue
elif [[ "${RET}" == "0" ]];then
continue
elif [[ "${RET}" == "1" ]];then
continue
else
# If the file hash is not found then it's entry is added in temporary file
add_file "${RET}" ${FILE}
continue
fi
done
}
# This will read the user input to collect list of directories to search for duplicate files
echo "Enter directory name to search: "
echo "Press [ENTER] when ready"
echo
read DIR
begin_search_and_deduplication "${DIR}"
# Delete the temporary files once done
rm -f $TMP_FILE
rm -f $DUP_FILE
我们可以执行脚本,该脚本将打印出我们要检查的目录列表,并删除Linux中的重复文件。
为了本文的目的,我创建了一些具有重复内容的文件。
# /tmp/remove_duplicate_files.sh Enter directory name to search: Press [ENTER] when ready /dir1 /dir2 /dir3 <-- This is my input (search duplicate files in these directories) /dir1/file1 is a duplicate of /dir1/file2 Which file you wish to delete? /dir1/file1 (or) /dir1/file2: /dir1/file2 File "/dir1/file2" deleted /dir1/file1 is a duplicate of /dir2/file101 Which file you wish to delete? /dir1/file1 (or) /dir2/file101: /dir2/file101 File "/dir2/file101" deleted
如我们所见,在提供的目录中找到重复文件时,脚本等待用户输入。
根据用户输入,将继续进行下一步。
怎么运行的?
我已在本节的大部分内容之前添加了注释,这些注释可以了解脚本如何删除重复的文件。
使用此哈希,我们可以将哈希与已计算的哈希列表进行比较。
如果匹配,则我们之前已经看过该文件的内容,因此可以删除它。
如果哈希值是新的,我们可以记录该条目并继续计算下一个文件的哈希值,直到所有文件都被哈希化为止。
现在,如果我们希望脚本自动查找并删除重复文件,则可以删除上面脚本中突出显示的块,只需使用del_file $FILE1,它将直接删除重复文件(如果找到)
脚本2:使用Shell脚本删除重复文件
其中我们将使用awk通过Shell脚本查找重复文件。
此代码将在目录中找到同一文件的副本,并删除该文件的一个副本以外的所有副本。
#!/bin/bash
# Filename: remove_duplicate.sh
# Description: Find and remove duplicate files and
# keep one sample of each file.
ls -lS --time-style=long-iso | awk 'BEGIN {
getline; getline;
name1=; size=
}
{
name2=;
if (size==)
{
"md5sum "name1 | getline; csum1=;
"md5sum "name2 | getline; csum2=;
if ( csum1==csum2 )
{
print name1; print name2
}
};
size=; name1=name2;
}' | sort -u > duplicate_files
cat duplicate_files | xargs -I {} md5sum {} | sort | uniq -w 32 | awk '{ print }' | sort -u > unique_files
echo Removing..
comm duplicate_files unique_files -3 | tee /dev/stderr | xargs rm
echo Removed duplicates files successfully.
我们必须在要查找和删除重复文件的目录内导航,然后执行脚本。
其中我想使用/dir1内的shell脚本查找重复的文件,因此我将使用cd/dir1然后执行不带任何参数的脚本
[root@centos-8 dir1]# /tmp/remove_duplicate.sh Removing.. file1_copy file2_copy Removed duplicates files successfully.
在"/dir1"下列出文件,并确保此处没有重复的文件。
创建了更多文件,供我们参考。
[root@centos-8 dir1]# ls -l total 20 -rw-r--r-- 1 root root 34 Jan 9 07:01 duplicate_files -rw-r--r-- 1 root root 16 Jan 9 06:56 duplicate_sample -rw-r--r-- 1 root root 5 Jan 9 07:00 file1 -rw-r--r-- 1 root root 6 Jan 9 07:00 file2 -rw-r--r-- 1 root root 12 Jan 9 07:01 unique_files
怎么运行的?
ls -ls列出了当前文件夹中文件的详细信息,并按文件大小排序。
--time-style = long-iso选项告诉ls以ISO格式打印日期。awk读取ls-lS的输出,并使用shell脚本对输入文本的列和行进行比较,以找到重复的文件。
使用Shell脚本查找重复文件的代码背后的逻辑如下:
我们列出了按大小排序的文件,因此相同大小的文件将相邻。
查找相同文件的第一步是查找具有相同大小的文件。
接下来,我们计算文件的校验和。
如果校验和匹配,则文件是重复的,并且一组重复项将被删除。在主处理之前执行awk的BEGIN {}块。
它读取"总计"行并初始化变量。
当awk读取并处理ls输出的其余部分时,大部分处理将在{}块中进行。
读取所有输入后,将执行END {}块语句。在" BEGIN"块中,我们读取第一行并存储名称和大小(它们分别是第八和第五列)。
当awk进入{}块时,其余的行将被一一读取。
该块将从当前行获得的大小与先前存储在size变量中的大小进行比较。
如果它们相等,则意味着两个文件在大小上是重复的,必须由md5sum进一步检查。读完该行后,整行位于$0中,每一列都位于
$1,$2,...,$n中。
其中我们将文件的md5sum校验和读入csum1和csum2变量。
" name1"和" name2"变量存储连续的文件名。
如果两个文件的校验和相同,则确认它们是重复的并被打印。我们计算重复项的md5sum值,并通过查找唯一的行,从每组重复项中打印一个文件,并使用-w 32比较每行中的md5sum(在md5sum输出中的前32个字符;通常,则md5sum输出由32个字符的哈希值和文件名组成)。
每组重复项中的一个示例被写入unique_files中。现在,我们需要删除
duplicate_files中列出的文件,不包括unique_files中列出的文件。
comm命令在duplicate_files中打印文件,但不在unique_files中打印文件。comm仅处理排序的输入。
因此,sort -u用于过滤duplicate_files和unique_files。tee命令用于将文件名传递给rm命令以及打印。
tee命令将其输入发送到stdout和一个文件。
我们还可以通过重定向到stderr将文本打印到终端上。
/dev/stderr是与stderr对应的设备(标准错误)。
通过重定向到" stderr"设备文件,发送到" stdin"的文本将作为标准错误打印在终端中。

