如何在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"的文本将作为标准错误打印在终端中。