如何编写一个 bash 单行代码,它将在同一 ext4 文件系统上从当前工作目录递归地查找具有相同内容、权限和所有者的二进制文件,并使用指向该文件的硬链接替换具有较旧访问时间的所有文件最近访问的文件和报告节省的磁盘空间(以千字节为单位)?
我目前所取得的成绩还不足以满足目标的要求。
#! /bin/sh
fdupes -r -p -o 'time' . | xargs file -i | grep binary | awk '{print $1}' | awk '{print substr($0,3)}' | sed 's/.\{1\}$//' | xargs rdfind -makehardlinks true
答案1
hardlink
可能无法满足所有要求,但它可以用于创建硬链接。它可以接受文件参数,而不仅仅是目录,而且它似乎总是将一组相同的文件按顺序链接到第一个文件。它还会忽略零大小的文件。
fdupes
准确选择所需内容,但不输出实际文件参数,而是输出段落模式输出,具有相同文件组,每个组以空行结束。
因此,为了确保 的确切选择fdupes
将被硬链接,我们必须hardlink
每个段落单独调用一次。避免出现两对相同的对象存在于不同所有者或具有不同权限的情况。当然,必须过滤文件中的二进制文件。
#!/bin/bash
unset arr i
while IFS= read -r f; do
# move file to array if binary
if file -i "$f" | grep -q "charset=binary"; then
arr[++i]="$f"
fi
# if end of paragraph and array has files, hardlink and unset array
if [[ "$f" == "" && "${arr[@]}" ]]; then
printf "\n => Hardlink for %d files:\n" "$i"
hardlink -n -c -vv "${arr[@]}"
unset arr i
fi
done < <(fdupes -rpio time .)
hardlink
with-n
参数模拟并且不写入任何内容,因此按原样测试上述内容并-n
稍后删除。
另外,带有换行符的文件名不会被处理,用空格测试似乎没问题。
答案2
终于得到了想要的结果。感谢@thanasisp。为此,您需要两个程序 fdupes 和 rdfind。
#!/bin/bash
unset arr i; while IFS= read -r f; do if file -i "$f" | grep -q "charset=binary"; then arr[++i]="$f"; fi; if [[ "$f" == "" && "${arr[@]}" ]]; then printf "\n => Hardlink for %d files:\n" "$i";rdfind -makehardlinks true "${arr[@]}" | grep "Total size is" | grep -P "[0-9]+" -o | head -1 | awk -v count="$i" '{print $1/count;}' | awk '{printf("%s kibibytes saved.\n",$1/1024)}'; unset arr i; fi; done < <(fdupes -rpio time .)