编写一个函数来用硬链接替换重复的文件

时间:2015-04-12 02:17:38

标签: linux bash

我需要编写一个bash脚本来迭代指定目录的文件,并用硬链接替换文件的副本。现在,我的整个函数看起来像这样:

#! /bin/bash
# sameln --- remove duplicate copies of files in specified directory

D=$1
cd $D           #go to directory specified as default input

fileNum=0       #loop counter

DIR=".*|*"
for f in $DIR           #for every file in the directory
do
    files[$fileNum]=$f      #save that file into the array
    fileNum=$((fileNum+1))      #increment the counter
done

for((j=0; j<$fileNum; j++))             #for every file
do
    if [ -f "$files[$j]" ]          #access that file in the array
    then
        for((k=0; k<$fileNum; k++))     #for every other file
        do
            if [ -f "$files[$k]" ]      #access other files in the array
            then
                test[cmp -s ${files[$j]} ${files[$k]}]      #compare if the files are identical
                [ln ${files[$j]} ${files[$k]}]          #change second file to a hard link
            fi
        done
    fi
done

基本上:

  • 遍历指定目录中深度为1的所有文件
  • 将文件内容放入数组
  • 将每个数组项与每个其他数组项进行比较,并将重复项替换为硬链接

测试目录有四个文件:a,b,c,d

a和b不同,但c和d是重复的(它们是空的)。运行脚本后,ls -l显示所有文件仍然只有1个硬链接,因此脚本似乎基本上什么也没做。

我哪里错了?

2 个答案:

答案 0 :(得分:1)

DIR=".*|*"
for f in $DIR           #for every file in the directory
do
    echo $f
done

此代码输出

.*|*

你不应该循环这样的文件。查看find命令。如您所见,您的代码无法正常工作,因为第一个循环已经出现故障。

顺便说一句,不要将变量全部大写,我相信这些变量都是为系统变量保留的。

答案 1 :(得分:1)

你可能会让自己的这个过程比必要时更难。已经有一个Linux命令fdupes扫描一个逐字节的目录,md5sum,date&amp;时间比较,以确定文件是否是彼此的重复。它可以轻松查找和返回重复文件组。只剩下使用结果了。

以下是使用此工具进行工作的快速示例。 注意此快速示例仅适用于包含空格的文件名。如果要处理包含空格的文件名,则必须对其进行修改。这是为了展示使用已经完成您想要的工具的方法。另外注意实际的ln命令在下面被注释掉了。该程序只是打印它会做什么。测试完成后,您可以在对结果满意后删除对ln命令的注释。

#! /bin/bash
# sameln --- remove duplicate copies of files in specified directory using fdupes

[ -d "$1" ] || {                  # test valid directory supplied
    printf "error: invalid directory '%s'.  usage: %s <dir>\n" "$1" "${0//\//}"
    exit 1
}

type fdupes &>/dev/null || {      # verify fdupes is available in path
    printf "error: 'fdupes' required. Program not found within your path\n"
    exit 1
}

pushd "$1" &>/dev/null            # go to directory specified as default input

declare -a files                  # declare files and dupes array
declare -a dupes

## read duplicate files into files array
IFS=$'\n' read -d '' -a files < <(fdupes --sameline .)

## for each list of duplicates
for ((i = 0; i < ${#files[@]}; i++)); do

    printf "\n duplicate files   %s\n\n" "${files[i]}"

    ## split into original files (no interal 'spaces' allowed in filenames)
    dupes=( ${files[i]} )

    ## for the 1st duplicate on
    for ((j = 1; j < ${#dupes[@]}; j++)); do

        ## create hardlink to original (actual command commented)
        printf "   ln -f %s %s\n" "${dupes[0]}" "${dupes[j]}"
        # ln -f "${dupes[0]}" "${dupes[j]}"

    done

done

exit 0

<强>输出/实施例

$ bash rmdupes.sh dat

 duplicate files   ./output.dat ./tmptest ./env4.dat.out

   ln -f ./output.dat ./tmptest
   ln -f ./output.dat ./env4.dat.out

 duplicate files   ./vh.conf ./vhawk.conf

   ln -f ./vh.conf ./vhawk.conf

 duplicate files   ./outfile.txt ./newfile.txt

   ln -f ./outfile.txt ./newfile.txt

 duplicate files   ./z1 ./z1cpy

   ln -f ./z1 ./z1cpy