摘自 Linux Shell 脚本攻略 第二章 命令之乐
tr
tr可以对 来自标准输入的内容进行字符替换、字符删除以及重复字符压缩
字符的大小写转换
$ echo "HELLO WHO IS THIS" | tr 'A-Z' 'a-z'
hello who is this
对字符进行加密
tr命令可以用来加密。ROT13是一个著名的加密算法。在ROT13算法中,字符会被移动13
个位置,因此文本加密和解密都使用同一个函数
$ echo "tr came, tr saw, tr conquered." | tr 'a-zA-Z' 'n-za-mN-ZA-M'
ge pnzr, ge fnj, ge pbadhrerq.
删除字符
$ echo "Hello 123 world 456" | tr -d '0-9'
Hello world
字符组补集
tr -c [set1] [set2]
如果只给出了set1,那么tr会删除所有不在set1中的字符。如果也给出了set2,tr会将不 在set1中的字符转换成set2中的字符。如果使用了-c选项,set1和set2必须都给出。如果-c 与-d选项同时出现,你只能使用set1,其他所有的字符都会被删除
$ echo hello 1 char 2 next 4 | tr -d -c '0-9 \n'
1 2 4
-d -c 同时使用时 只保留给定set字符中的字符
$ echo hello 1 char 2 next 4 | tr -c '0-9' ' '
1 2 4
只使用-c 时 将非字符集替换
用tr压缩字符
$ echo "GNU is not UNIX. Recursive right ?" |tr -s ' '
GNU is not UNIX. Recursive right ?
删除字符中重复的空格
tr的灵活运用
sum.txt
$ cat sum.txt
1
2
3
4
5
计算sum文件中所有数的和
$ cat sum.txt |echo $[ `tr '\n' '+'` 0]
15
tr ‘\n’ ‘+’ 将换行替换成+ 得到表达式 1+2+3+4+5+
再将其与0 拼接 得到表达式 1+2+3+4+5+0
最后运行该表达式得到总数
另外一个例子
test.txt
$ cat test.txt
first 1
second 2
third 3
计算test中数字的总和
$ cat test.txt |tr -d [a-z]|echo "total $[ `tr ' ' '+'`]"
total 6
利用tr的-d选项删除文件中的字母,然后将空格替换成+
可以使用的字符类
- alnum:字母和数字。
- alpha:字母。
- cntrl:控制(非打印)字符。 digit:数字。
- graph:图形字符。
- lower:小写字母。
- print:可打印字符。
- punct:标点符号。
- space:空白字符。
- upper:大写字母。
- xdigit:十六进制字符。
$ echo 'coco is handsome 123 !' |tr -d [:alnum:]
!
md5sum
计算文件的md5sum
coco.log
$ cat coco.log
coco is handsome
$ md5sum coco.log
7fdc4a7ed1e76c6e1e1ac2ae24fd2068 coco.log
保存校验信息
$ md5sum coco.log > coco.md5
$ md5sum -c coco.md5
coco.log: OK # 校验 ok
$ vi coco.log
$ cat coco.log
coco is handsome !
$ md5sum -c coco.md5
coco.log: FAILED # 原文件中添加! 校验 fail
md5sum: WARNING: 1 computed checksum did NOT match
递归校验
md5deep或sha1deep命令可以遍历目录树,计算其中所有文件的校验和。你的系统中可能 并没有安装这两个程序。可以使用apt-get或yum来安装md5deep软件包
$ md5deep -rl directory_path > directory.md5
# -r使用递归遍历
# -l使用相对路径。默认情况下,md5deep会输出文件的绝对路径
也可以结合find 命令进行递归校验
$ find directory_path -type f –print0 | xargs -0 md5sum >> directory.md5
md5与SHA-1都是单向散列算法,均无法逆推出原始数据。两者通常用于为特定数据生成 唯一的密钥
sort
sort命令能够对文本文件和stdin进行排序。它可 以配合其他命令来生成所需要的输出。uniq经常与sort一同使用,提取不重复(或重复)的行
排序一组文件
$ sort file1.txt file2.txt > sorted.txt
# 或者
$ sort file1.txt file2.txt -o sorted.txt
按照数字排序
$ sort -n file.txt
按照逆序排序
$ sort -r file.txt
按照月份排序
$ sort -M months.txt
合并两个已排序过的文件
$ sort -m sorted1 sorted2
找出已排序文件中不重复的行
$ sort file1.txt file2.txt | uniq
检查文件是否已经排序过
$ sort -C filename
依据键或者列排序
data.txt
$ cat data.txt
1 mac 2000
2 winxp 4000
3 bsd 1000
4 linux 1000
- 根据第一列,以逆序形式排序
$ sort -nrk 1 data.txt
4 linux 1000
3 bsd 1000
2 winxp 4000
1 mac 2000
nr 表明按照数字顺序,采用逆序形式排序
- 根据第二列进行排序
$ sort -k 2 data.txt
3 bsd 1000
4 linux 1000
1 mac 2000
2 winxp 4000
- 根据第二列的第二个字符位进行排序
$ sort -bk 2.2,2.3 data.txt
1 mac 2000
2 winxp 4000
4 linux 1000
3 bsd 1000
与xargs组合使用
为了使sort的输出与以\0作为终止符的xargs命令相兼容,采用下面的命令
$ sort -z data.txt | xargs -0
uniq
uniq命令可以从给定输入中(stdin或命令行参数指定的文件)找出唯一的行,报告或删除 那些重复的行
uniq只能作用于排过序的数据,因此,uniq通常都与sort命令结合使用
$ cat sorted.txt bash
bash
foss
hack
hack
$ uniq sorted.txt bash
bash
foss
hack
只显示唯一的行
$ uniq -u sorted.txt
bash
foss
# 或者
$ sort unsorted.txt | uniq -u
统计各行出现的次数
$ sort sorted.txt |uniq -c
1 bash
1 foss
2 hack
找出重复的行
$ sort sorted.txt |uniq -d
hack
灵活使用
uniq -s -w 没弄懂 先空着
mktemp
创建临时文件
$ mktemp
/tmp/tmp.p2LSrnqLnY
创建临时目录
$ mktemp -d
/tmp/tmp.vz0dURj7ou
仅生成文件名 不创建对应文件
$ mktemp -u
/tmp/tmp.s1kyZszp1i
基于模板创建临时文件名
$ mktemp test.XXX
test.EH2
如果提供了定制模板,X会被随机的字符(字母或数字)替换。注意,mktemp正常工作的前 提是保证模板中至少要有3个X
split
split命令可以用来分割文件。该命令接受文件名作为参数,然后创建出一系列体积更小的 文件,其中依据字母序排在首位的那个文件对应于原始文件的第一部分,排在次位的文件对应于 原始文件的第二部分,以此类推
分割文件
$ split -b 10k data.file
$ ls
data.file xaa xab xac xad xae xaf xag xah xai xaj
split默认使用字母后缀。如果想使用数字后缀,需要使用-d选项。此外, -a length 可以指定后缀长度
分割文件并指定后缀格式
$ split -b 10k data.file -d -a 4
$ ls
data.file x0009 x0019 x0029 x0039 x0049 x0059 x0069 x0079
分割文件指定前后缀格式
$ split -b 10k data.file -d -a 4 split_file
$ ls
data.file split_file0002 split_file0005 split_file0008 split_file0000 split_file0003 split_file0006 split_file0009 split_file0001 split_file0004 split_file0007
按照行数分割文件
分割成多个文件,每个文件包含10行
$ split -l 10 data.file
csplit的使用
$ csplit server.log /SERVER/ -n 2 -s {*} -f server -b "%02d.log"
$ rm server00.log
$ ls
server01.log server02.log server03.log server.log
- /SERVER/ 用来匹配特定行,分割过程即从此处开始。
- /[REGEX]/ 用于描述文本模式。它从当前行(第一行)一直复制到(但不包括)包含SERVER
的匹配行。 - {*} 表示根据匹配重复执行分割操作,直到文件末尾为止。可以用{整数}的形式来指定分
割执行的次数。 - -s 使命令进入静默模式,不打印其他信息。
- -n 指定分割后的文件名后缀的数字个数,例如01、02、03等。
- -f 指定分割后的文件名前缀(在上面的例子中,server就是前缀)。
- -b 指定后缀格式。例如%02d.log,类似于C语言中printf的参数格式。在这里:文件
名 = 前缀 + 后缀,也就是server + %02d.log。
根据拓展名切分文件名
提取文件名
$ name=coco.log
$ echo ${name%.*}
coco
$ echo ${name#*.}
log
${VAR%.*} 的含义如下
从$VAR中删除位于%右侧的通配符(在上例中是.*)所匹配的字符串。通配符从右向左进 行匹配。
给VAR赋值,即VAR=sample.jpg。通配符从右向左匹配到的内容是.jpg,因此从$VAR中 删除匹配结果,得到输出sample。
%属于非贪婪(non-greedy)操作。它从右向左找出匹配通配符的最短结果。还有另一个操作 符%%,它与%相似,但行为模式却是贪婪的,这意味着它会匹配符合通配符的最长结果
$ VAR=hack.fun.book.txt
$ echo ${VAR%.*}
hack.fun.book
$ echo ${VAR%%.*}
hack
多个文件的重命名与移动
#!/bin/bash
#文件名: rename.sh
#用途: 重命名 .jpg 和 .png 文件
count=1;
for img in `find . -iname '*.png' -o -iname '*.jpg' -type f -maxdepth 1` # 在当前目录查找多有 png 以及 jpg文件
do
new=image-$count.${img##*.} # 拼接新名字 image-1.jpg
echo "Renaming $img to $new"
mv "$img" "$new"
let count++
done
拼写检查与词典操作
#!/bin/bash
#文件名: checkword.sh
word=$1
grep "^$1$" /usr/share/dict/british-english -q if [ $? -eq 0 ]; then # 通过grep 查找文件中是否存在文件中
echo $word is a dictionary word;
else
echo $word is not a dictionary word;
fi
aspell
$ echo 'coco is handsoma' |aspell list
handsoma
交互输入自动化
#!/bin/bash
# backup.sh
# 使用后缀备份文件。不备份以~开头的临时文件
read -p " What folder should be backed up: " folder
read -p " What type of files should be backed up: " suffix
find $folder -name "*.$suffix" -a ! -name '~*' -exec cp {} $BACKUP/$LOGNAME/$folder
echo "Backed up files from $folder to $BACKUP/$LOGNAME/$folder"
$ echo -e "notes\ndocx\n" | ./backup.sh
Backed up files from notes to /BackupDrive/MyName/notes
expect
#!/usr/bin/expect
# 不是!/bin/bash 解释器
# 文件名: automate_expect.tcl
spawn ./backup .sh # 执行backup.sh 脚本
expect {
"*folder*" {
send "notes\n"
exp_continue # 未检索到folder 也会继续往下执行
}
"*type*" {
send "docx\n"
exp_continue
}
}
利用并行进程加速命令执行
#/bin/bash
#文件名: generate_checksums.sh
PIDARRAY=()
for file in File1.iso File2.iso;do
md5sum $file &
PIDARRAY+=("$!") # $! Shell最后运行的后台Process的PID(后台运行的最后一个进程的进程ID号)
done
wait ${PIDARRAY[@]} # 等待后台结束后退出脚本
检查目录以及其中的文件与子目录
查看目录的树状图
$ find . -exec sh -c 'echo -n {} | tr -d "[:alnum:]_.\-" | tr "/" " "; basename {}' \;
.
.idea
workspace.xml
misc.xml
.gitignore
inspectionProfiles
Project_Default.xml
profiles_settings.xml
modules.xml
for_fun.iml
aa.json
coco.py
main.py
text.txt
! 最后basename 输出文件名 没明白怎么添加的行首空格
查看各文件夹下文件数量
for d in `find . -type d`;do # 获取文件夹列表
echo `find $d -type f |wc -l` file in $d # 遍历文件夹内数量 统计
done
11 file in .
7 file in ./.idea
2 file in ./.idea/inspectionProfiles