批量重命名和移动文件
#!/bin/bash
#filename: rename.sh
#desc: rename .jpg & .png
count=1;
for img in `find . -iname '*.png' -o -iname '*.jpg' -type f -maxdepth 1`
do
new=image-$count.${img##*.}
echo "renaming $img to $new"
mv "$img" "$new"
let count++
done
rename 's/ /_/g' *
#把文件名中的空格替换为字符'_'
拼写检查与词典操作
#!/bin/bash
#文件名: checkword.sh
word=$1
grep "^$1$" /usr/share/dict/british-english -q
if [ $? -eq 0 ]; then
echo $word is a dictionary word;
else
echo $word is not a dictionary word;
fi
在grep中,^ 标记着单词的开始,$ 标记着单词的结束。-q 禁止产生任何输出。
并行进程加速命令
#!/bin/bash
PIDARRAY=()
for file in File1.iso File2.so
do
md5sum $file &
PIDARRAY+=("$!")
done
wait ${PIDARRAY[@]}
我们利用了Bash的操作符&,它使得shell将命令置于后台并继续执行脚本。这意味着一旦循环结束,脚本就会退出,而md5sum命令仍在后台运行。为了避免这种情况,我们使用!来获得进程的PID,在Bash中,!保存着最近一个后台进程的PID。我们这些PID放入数组,然后使用wait命令等待这些进程结束。
文本文件的交集与差集
comm A.txt B.txt -3 | sed 's/^\t//'
#A,B 文件的求差
在生成统一输出时,sed命令通过管道获取comm的输出。它删除行首的 \t字符。sed中的s表示替换(substitute)。/^\t/ 匹配行前的 \t(^是行首标记)。//(两个/操作符之间没有任何字符)是用来替换行首的\t的字符串。如此一来,就删除了所有行首的\t。
查找并删除重复文件
# !/bin/bash
# 文件名: remove_duplicates.sh
# 用途: 查找并删除重复文件,每一个文件只保留一份
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.
ls -lS对当前目录下的所有文件按照文件大小进行排序,并列出文件的详细信息。awk读取ls -lS的输出,对行列进行比较,找出重复文件。
我们将文件依据大小排序并列出,这样大小接近的文件就会排列在一起。识别大小相同的文件是我们查找重复文件的第一步。接下来,计算这些文件的校验和。如果校验和相同,那么这些文件就是重复文件,将被删除。
第1行输出告诉我们文件数量,这个信息在本例中没什么用处。我们用getline读取第1行,然后丢弃。由于需要对每一行及其下一行来比对文件大小,因此用getline读取长文件列表的第一行,并存储文件名和大小(它们分别是第8列和第5列)。这样我们就先得到了一行。接下来,awk进入{}语句块(在这个语句块中读取余下的文本行),读取到的每一行文本都会执行该语句块。它将当前行中读取到的文件大小与之前存储在变量size中的值进行比较。如果相等,那就意味着两个文件至少在大小上是相同的,随后再用md5sum执行进一步的检查。
在awk中,外部命令的输出可以用下面的方法读取:
“cmd”| getline
随后就可以在0中获取命令的输出,在1,2,…n中获取命令输出中的每一列。我们将文件的md5sum保存在变量csum1和csum2中。变量name1和name2保存文件列表中位置连续的文件名。如果两个文件的校验和相同,那它们肯定是重复文件,其文件名会被打印出来。
我们需要从每组重复文件中找出一个文件,这样就可以删除其他副本了。计算重复文件的md5sum,从每一组重复文件中打印出其中一个。这是通过-w 32比较每一行的md5sum(md5sum输出中的前32个字符,md5sum的输出通常由32个字符的散列值和文件名组成),然后找出那些不相同的行。这样,每组重复文件中的一个采样就被写入duplicate_sample。
现在需要将duplicate_files中列出的、且未包含在duplicate_sample之内的全部文件删除。这些文件由comm命令负责打印出来。我们可以使用差集操作来实现(参考3.3节)。
comm通常只接受排序过的文件。所以,在重定向到duplicate_files和duplicate_sample之前,首先用sort -u作为一个过滤器。
tee命令在这里有一个妙用:它在将文件名传递给rm命令的同时,也起到了print的作用。tee将来自stdin的行写入文件,同时将其发送到stdout。我们也可以将文本重定向到stderr来实现终端打印功能。/dev/stderr是对应于stderr(标准错误)的设备。通过重定向到stderr设备文件,来自stdin的文本将会以标准错误的形式出现在终端中。
charttr 设置文件
chattr +i file
#文件设置为不可修改
文件统计信息
#! /bin/bash
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 : ${statarrat["$ftype"]}
done
在脚本中声明了一个关联数组statarray,这样可以用文件类型作为数组索引,将每种文件类型的数量存入数组。每次遇到一个文件类型,就用let增加计数。find命令以递归的方式获取文件路径列表。脚本中的ftype=’file -b “$line”’使用file命令获得文件类型信息。选项-b告诉file命令只打印文件类型(不包括文件名)。输出的文件类型信息包含很多细节,比如图像编码以及分辨率(如果是图像文件的话)。对于这些细节我们并不感兴趣,我们只需要基本的信息就够了。各种细节信息是由逗号分隔的,例如:
$ file a.out -b
ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked (uses shared libs), for GNU/Linux 2.6.15, not stripped
我们只需要从上面这些细节中提取ELF 32-bit LSB executable。因此我们使用cut -d,-f1,指明以逗号作为定界符,并且只打印第一个字段。
done<<(find $path –type f –print);是一段很重要的代码。它的执行逻辑如下:
while read line;
do something
done < filename
我们不用filename,而是用find命令的输出。
<(find $path -type f -print)等同于文件名。只不过它用子进程输出来代替文件名。注意,第一个<用于输入重定向,第二个<用于将子进程的输出装换成文件名。在两个<之间有一个空格,避免shell将其解释为<<操作符。
${!statarray[@]}用于返回一个数组索引列表。
diff 生成目录的差异信息
diff -Naur directory1 directory2
-N: 将所有确实的文件视为空文件
-a: 将所有文件视为文本文件
-u:生成一体化输出
-r: 遍历目录下的所有文件
tail 终端持续更新
tail -f growing_file
tail -f /var/log/messages
dmsg | tail -f
#假设我们正在读取一个不断增长的文件,进程Foo一直在向该文件追加数据,那么tail -f 就会一直执行到进程Foo结束
PID=$(pidof Foo)
tail -f file --pid $PID
我们经常会运行dmeg 查看内核的环形缓冲区消息,要么是调试USB设备,要么是查看sdX(X是对应于SCSI磁盘的sd设备的次序列号)。tail -f也可以加入一个睡眠间隔 -s,这样我们就可以设置监视文件更新的时间间隔。