五 Linux Shell常用命令[sort,uniq,mktemp,split,csplit]
一 排序
sort命令能够对文本文件和stdin进行排序.它可以配合其他命令来生成所需要的输出.uniq经常和sort一同使用,提取不重复(或重复)的行.
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 file.txt #合并两个已排序过的文件 sort -m sorted1 sorted2 #找出已排序文件中不重复的行 sort file1.txt file2.txt | uniq
#检查文件是否已经排序过
#!/bin/bash
#功能描述:排序
sort -C filename ;
if [ $? -eq 0 ]; then
echo Sorted;
else
echo Unsorted;
fi
#####测试数据#####
[root@rwwh rh]# cat data.txt
1 mac 2000
2 winxp 4000
3 bsd 1000
4 linux 1000
#依照第一列,逆序形式排序
[root@rwwh rh]# sort -nrk 1 data.txt
4 linux 1000
3 bsd 1000
2 winxp 4000
1 mac 2000
#依照第二列进行排序
[root@rwwh rh]# sort -k 2 data.txt
3 bsd 1000
4 linux 1000
1 mac 2000
2 winxp 4000
#注意:sort命令对于字母表排序和数字排序有不同的处理方式,因此,如果采用数字顺序排序,就应该明确地给出-n选项
#说明:-k后的整数指定了文本文件中的某一列.列与列直接由空格分隔.若需要将特定范围内的一组字符(例如.第二列中的第4-5个字符)
#作为键,应该使用点号分隔的两个整数来定义一个字符位置,然后将范围内的第一个字符和最后一个字符用逗号连接起来.
#若需要忽略空格之类的多余字符并以字典排序
sort -bd unsorted.txt
###这里想不通,回头再想想
uniq的用法
uniq 命令可以从给定输入中( stdin 或命令行参数指定的文件)找出唯一的行,报告或删除那些重复的行.uniq只能作用于排过序的数据,因此uniq通常都与sort命令结合使用
##测试数据 [root@rwwh rh]# cat sort11.txt hack bash foss hack hack #删除重复的行 [root@rwwh rh]# sort sort11.txt |uniq bash foss hack #只显示不重复的行 [root@rwwh rh]# sort sort11.txt |uniq -u bash fos #只显示重复的行 [root@rwwh rh]# sort sort11.txt |uniq -d hack #统计各行在文件中出现的次数 [root@rwwh rh]# sort sort11.txt |uniq -c 1 bash 1 foss 3 hack
将命令输出作为 xargs 命令的输入时,最好为输出的各行添加一个0值字节(zero-byte)
终止符。使用 uniq 命令的输入作为 xargs 的数据源时,同样应当如此。如果没有使用0值字节终
止符,那么在默认情况下, xargs 命令会用空格来分割参数。例如,来自 stdin 的文本行“this is
a line”会被 xargs 视为4个不同的参数。如果使用0值字节终止符,那么 \0 就被作为定界符,此时,
包含空格的行就能够被正确地解析为单个参数
-z 选项可以生成由0值字节终止的输出:
$ uniq -z file.txt
下面的命令将删除所有指定的文件,这些文件的名字是从files.txt中读取的:
$ uniq -z file.txt | xargs -0 rm
如果某个文件名出现多次, uniq 命令只会将这个文件名写入 stdout 一次,这样就可以避免
出现 rm: cannot remove FILENAME: No such file or directory
#看不懂,回头再想想
二 临时文件命名与随机数
shell脚本经常需要存储临时数据。最适合存储临时数据的位置是 /tmp(该目录中的内容在系统重启后会被清空)。有两种方法可以为临时数据生成标准的文件名
mktemp 命令的用法非常简单。它生成一个具有唯一名称的文件并返回该文件名(如果创建
的是目录,则返回目录名)。
如果提供了定制模板, X 会被随机的字符(字母或数字)替换。注意, mktemp 正常工作的前
提是保证模板中至少要有3个 X 。
#创建临时文件 [root@rwwh rh]# filename=`mktemp` [root@rwwh rh]# echo $filename /tmp/tmp.hCUnPHK3KA #创建临时目录 [root@rwwh rh]# dirname=`mktemp -d` [root@rwwh rh]# echo $dirname /tmp/tmp.fp04cPS9yl #若仅仅想生成文件名,不希望创建实际的文件或目录 [root@rwwh tmp.fp04cPS9yl]# tmpfile=`mktemp -u` [root@rwwh tmp.fp04cPS9yl]# echo $tmpfile /tmp/tmp.UGZdP6NcBt
#基于模板创建临时文件名
[root@rwwh tmp.fp04cPS9yl]# mktemp test.XXX
test.8EL
[root@rwwh tmp.fp04cPS9yl]# mktemp XXX.txt
91t.txt
三 分割文件与数据
split
split命令可以用来分割文件.该命令接受文件名作为参数,然后创建出一系列体积更小的文件,其中依据字母序排在首位的那个文件对应于原始文件的第一部分,排在次序的文件对应于原始文件的第二部分,以此类推.
例如,通过指定分割大小,可以将100KB的文件分成一系列10KB的小文件。在 split 命令中,除了 k (KB),我们还可以使用 M (MB)、 G (GB)、 c (byte)和 w (word)
$ split -b 10k data.file $ ls data.file xaa xab xac xad xae xaf xag xah xai xaj 上面的命令将data.file分割成了10个大小为10KB的文件。这些新文件以 xab 、 xac 、 xad 的形 式命名。 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
strtok.c
split_file0000 split_file0003 split_file0006 split_file0009
split_file0001 split_file0004 split_file0007
#若不想按照数据块大小,而是根据行数分割文件的话,可以使用-l num_of_lines:
# 分割成多个文件,每个文件包含10 行
$ split -l 10 data.fil
csplit
csplit 实用工具能够基于上下文来分隔文件。它依据的是行计数或正则表达式。这个工具对于日志文件分割尤为有用.
#测试数据 $ cat server.log SERVER-1 [connection] 192.168.0.1 success [connection] 192.168.0.2 failed [disconnect] 192.168.0.3 pending [connection] 192.168.0.4 success SERVER-2 [connection] 192.168.0.1 failed [connection] 192.168.0.2 failed [disconnect] 192.168.0.3 success [connection] 192.168.0.4 failed SERVER-3 [connection] 192.168.0.1 pending [connection] 192.168.0.2 pending [disconnect] 192.168.0.3 pending [connection] 192.168.0.4 failed #需求:将这个日志文件分割成server1.log、server2.log和server3.log,这些文件的内容分别取自原文件中不同的 SERVER 部分 #实现 $ 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 。 因为分割后得到的第一个文件没有任何内容(匹配的单词就位于文件的第一行中),所以我 们删除了server00.log
四 根据扩展名切分文件名
借助%操作符可以从name.extension这种格式中提取name部分(文件名)
[root@rwwh ~]# file_jpg="sample.jpg"
${VAR.*}含义如下:
①从$VAR中删除位于%右侧的通配符(在上例中是.*)所匹配的字符串,通配符从右往左进行匹配.
②给VAR赋值,即VAR=sample.jpg.通配符从右往左匹配到的内容是.jpg,因此从$VAR中删除匹配结果,得到输出sample [root@rwwh ~]# name=${file_jpg%.*} [root@rwwh ~]# echo File name is: $name File name is: sample
%属于非贪婪(non-greedy)操作.它从右向左找出匹配通配符的最短结果.还有另一个操作符%%,它与%相似,但行为模式确实贪婪的,这意味着它会匹配符合通配符的最长结果
[root@rwwh ~]# VAR=hack.fun.book.txt
[root@rwwh ~]# echo ${VAR%.*}
hack.fun.book
[root@rwwh ~]# echo ${VAR%%.*}
hack
借助#操作符可以提取出扩展名,这个操作符与%相似,不过求值方向是从左向右
${VAR#*.}的含义如下:
从$VAR中删除位于#右侧的通配符(即*.)从左向右所匹配的字符串
[root@rwwh ~]# extension=${file_jpg#*.} [root@rwwh ~]# echo Extension is:$extension Extension is:jpg
和 %% 类似, # 也有一个对应的贪婪操作符 ##,## 从左向右进行贪婪匹配,并从指定变量中删除匹配结果
[root@rwwh ~]# VAR=hack.fun.book.txt
[root@rwwh ~]# echo ${VAR#*.}
fun.book.txt
[root@rwwh ~]# echo ${VAR##*.}
txt
#假定URL为www.google.com
$ echo ${URL%.*} # 移除.* 所匹配的最右边的内容
www.google
$ echo ${URL%%.*} # 将从右边开始一直匹配到最左边的.* (贪婪操作符)移除
www
$ echo ${URL#*.} # 移除 *. 所匹配的最左边的内容
google.com
$ echo ${URL##*.} # 将从左边开始一直匹配到最右边的*. (贪婪操作符)移除
com