shell学习3

目录

一、查找并删除重复文件

二、列举文件类型统计信息

三、只列出目录


一、查找并删除重复文件

重复文件是同一个文件的多个副本。有时候我们需要删除重复的文件,只保留其中一份。通过查看文件内容来识别重复文件是件挺有意思的活儿。可以结合多种shell工具来完成这项任务。在这则攻略中,我们讨论如何查找重复文件并根据查找结果执行相关的操作。

我们可以通过比较文件内容来识别它们。校验和是依据文件内容来计算的,内容相同的文件自然会生成相同的校验和,因此,我们可以通过比较校验和来删除重复文件。

 

 脚本:

#!/bin/bash
ls -lS --time-style=long-iso | awk 'BEGIN {
getline; getline;
name1=$8; size=$5
}
{
name2=$8;
if (size==$5)
{
"md5sum "name1 | getline; csum1=$1;
"md5sum "name2 | getline; csum2=$1;
if ( csum1==csum2 )
{
print name1; print name2
}
};
size=$5; name1=name2;
}' | sort -u > duplicate_files

cat duplicate_files | xargs -I {} md5sum {} | sort | uniq -w 32 | awk '{ print
"^"$2"$" }' | sort -u > duplicate_sample

echo Removing..
comm duplicate_files duplicate_sample -2 -3 | tee /dev/stderr | xargs rm
echo Removed duplicates files successfully.

运行结果:

 

代码理解:

1、ls -lS   对当前目录下的所有文件按照文件大小进行排序,并列出文件的详细信息

--time-style=long-iso  显示日期和时间(包括年),以长格式显示yyyy-mm-dd hh:mm:ss

 

2、awk

awk 'BEGIN {
getline; getline;
name1=$8; size=$5
}
{
name2=$8;
if (size==$5)
{
"md5sum "name1 | getline; csum1=$1;
"md5sum "name2 | getline; csum2=$1;
if ( csum1==csum2 )
{
print name1; print name2
}
};
size=$5; name1=name2;
}'

第一个 getline 读取第1行,然后丢弃。也就是说第一个getline会读取到total 16 并删除。

第二个getline 读取到第2行,然后把第2行的第八列赋值给name1,把第5列赋值给size。

第二个getline 读取到第3行,然后把第三行的第八列赋值给name2,把第5列与size进行比较。如果比较结果是大小相等。那么md5sum name1 就会计算出name1的md5值,并把结果的第一列(结果有两列,第一列是文件的md5值,第二列是文件名。)赋值给csum1;类似的,csum2变量存储的就是name2文件的md5值。如果name1和name2的文件的md5值是相同的,就打印name1和name2.否则就把当前行的第五列赋值给size。当前行的第八列赋值给name1。也就是说,第2行和第3行比较,第3行和第2行比较。

在 awk 中,外部命令的输出可以用下面的方法读取:"cmd"| getline

3、sort

sort 默认是从小到大排序

sort -u  可以排序去重

4、xargs

xargs -I    指定每一项命令行参数的替代字符串.

 cat duplicate_files | xargs -I {} md5sum {}等价于test  md5sum、test_copy1  md5sum。

5、uniq -w  32

将每一行的前32个字符进行比较,如果相同就删除。 (md5sum输出中的前32个字符, md5sum 的输出通常由32个字符的散列值和文件名组成)

 

6、tee /dev/stderr

tree 命令在这里有一个妙用:它在将文件名传递给 rm 命令的同时,也起到了 print 的作用。
tee 将来自 stdin 的行写入文件,同时将其发送到 stdout 。我们也可以将文本重定向到 stderr
来实现终端打印功能。/dev/stderr是对应于 stderr (标准错误)的设备。通过重定向到 stderr
设备文件,来自 stdin 的文本将会以标准错误的形式出现在终端中


二、列举文件类型统计信息

编写一个脚本,使它能够遍历目录中所有的文件,并生成一份关于文件类型细节以及每种文件类型数量的报告。

脚本:

#!/bin/bash
# 文件名:filestat.sh
if [ $# -ne 1 ];
then
echo "Usage is $0 basepath";
exit
fi

path=$1
declare -A statarray;

while read line;
do
ftype=`file -b "$line" | cut -d, -f1`
let statarray["$ftype"]++;
done < <(find $path -type f -print)

echo ============ File types and counts =============
for ftype in "${!statarray[@]}";
do
echo $ftype : ${statarray["$ftype"]}
done

运行:

 

 代码理解:

1、declare -A statarray;

声明一个关联数组statarray

2、find $path -type f -print

将当某目录及其子目录中的所有文件列出并打印

 

3、file -b

辨识文件类型,列出辨识结果时,不显示文件名称

 

4、cut -d , -f1

以逗号为分割符,取出第一个。

 

5、let statarray["$ftype"]++;

用文件类型作为数组索引,将每种文件类型的数量存入数组。每次遇到一个文件类型,就用 let 增加计数

 6、${!statarray[@]} 

列出关联数组的所有索引

7、<(find $path -type f -print)

<(find $path -type f -print) 等同于文件名。只不过它用子进程输出来代替文件名。
注意,第一个<用于输入重定向,第二个<用于将子进程的输出装换成文件名。在两个<之间有一
个空格,避免shell将其解释为<<操作符。


三、只列出目录

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值