1.2 基础运维类命令
1.2.1 如何对文件打包、压缩与解压缩
Linux运维中,对于压缩常用的命令主要有tar、gzip/gunzip和bzip2/bunzip2,而使用最多的就是tar指令,tar指令参数非常多,功能也很强大,但使用最频繁的参数只有几个,也就是只需要记住这几个参数就能轻松玩转tar命令了。
1.文件归档并压缩解压命令tar
tar是Linux下经常使用的归档工具,可以对文件或者目录进行打包归档,归成一个文件,但是并不进行压缩。其格式如下:
tar命令的选项很多,这里列出一些经常用到的主选项,见表1-1。
表1-1 tar命令主选项含义
辅助选项的详细信息见表1-2。
表1-2 tar命令辅助选项含义
下面看几个tar命令使用的例子。
1)将/etc目录下的所有文件打包,并显示打包的详细文件,设置打包文件名为etc.tar,同时保存文件到/opt目录下。
这里的档案名为etc.tar,档案名可以随意起,Linux上利用tar命令打包出来的档案文件一般用.tar作为标识。
2)将/etc目录下的所有文件打包并压缩,然后显示打包的详细文件,设置打包文件名为etc.tar.gz,同时保存文件到/opt目录下。
zcvf选项表示在打包完成后调用gzip命令对档案文件进行压缩,这里的档案名etc.tar.gz也可以随意起,.tar表示是用tar命令打包的,.gz表示调用了gzip命令进行了压缩。同理,jcvf选项表示在打包完成后调用bzip2命令对档案文件进行压缩,档案命名标识中.bz2表示调用了bzip2命令进行了压缩处理。
这里对档案文件的命名没有硬性的规定,上面采用的命名规则可以很方便地让人们知道文件的类型以及对应的解压方式,因为压缩方式不同,解压方式也是不同的。同时,这种规则也是大家都默许了的一种潜规则。如果读者不喜欢这种规则,完全可以按照自己喜欢的方式命名档案文件。
3)查阅上面/opt/etc.tar.gz压缩包的内容。
注意:etc.tar.gz可能包含很多个文件,无法一个屏幕显示完毕,这时可以使用more命令,例如,tar-zxvf/opt/etc.tar.gz|more。
4)将/opt/etc.tar.gz解压到/usr/local/src下。
一般情况下,可以把/opt/etc.tar.gz在任何地方解压,这里首先切换到了/usr/local/src目录下,然后解压/opt/etc.tar.gz,因此/usr/local/src/etc目录就是解压的目录。
5)将/etc目录下的所有文件打包备份到/opt目录下,并保存每个文件的权限。
6)在/opt目录下,仅解压/opt/etc.tar.gz压缩文件中的/etc/inittab文件。
首先可以通过tar-ztvf查看etc.tar.gz文件中包含的文件,然后找到需要解压的文件,通过上面的方式解压。后面指定的需要解压出来的文件一定要是通过tar-ztvf显示出来的文件完整路径。这样就在/opt目录下解压出了一个etc目录,而etc目录下的inittab就是需要的文件。
7)打包备份/var/log目录中2019/7/21以后的文件。
8)打包备份/home目录和/etc目录,但是不备份/home下的ixdba目录。
9)将/etc目录打包压缩后直接解压到/opt目录下,而不生成打包的档案文件。
在上面的命令中,紧跟在f后面的-是将创建的档案文件输出到标准输出上,|在Linux下表示管道符,命令最后的-表示将tar命令通过管道传入的档案文件作为需要解压的数据来源。
在实际使用中,tar命令经常用来打包备份,使用的方法是编写一个自动备份脚本,定期对指定的文件或目录进行压缩、打包备份,这是运维最基础的工作。要编写这个脚本,核心就是通过tar命令对需要备份的文件进行打包和压缩。下面就给出一个基于tar进行自动备份的shell脚本,内容如下:
此脚本的执行过程是:先在指定的备份目录下创建一个基于用户的目录,然后开始进行tar打包、压缩备份,备份的同时也把备份的日志一起打包进备份文件中。备份成功后,将备份过程产生的日志文件删除,同时一并删除备份文件中超过指定时间的文件。最后将备份的文件传输到远程主机上。
传输到远程主机是通过rsync命令来实现的,因为rsync用来使传输文件更加精准,它可以校验文件的完整性,但前提是要打通备份机与远程备份机的无密码登录。
2.文件压缩解压命令gzip/gunzip
gzip/gunzip表示将一般的文件进行压缩或者解压。压缩文件预设的扩展名为.gz,其实gunzip就是gzip的硬链接,因此无论是压缩或者解压都可以通过gzip来实现。
注意:gzip只能对文件进行压缩,不能压缩目录,即使指定压缩的目录,也只能压缩目录内的所有文件。
其格式如下:
gzip命令的选项及其说明见表1-3。
表1-3 gzip命令选项含义
下面看几个使用例子。
1)首先将/etc目录下的所有文件以及子目录进行压缩,备份压缩包etc.zip到/opt目录,然后对etc.zip文件进行gzip压缩,设置gzip的压缩级别为9。
2)查看上述etc.zip.gz文件的压缩信息。
3)解压上述etc.zip.gz文件到当前目录。
通过上面的示例可以知道gzip-d等价于gunzip命令。
3.文件压缩解压缩命令bzip2/bunzip2
bzip2/bunzip2表示对文件进行压缩与解压缩。此命令类似于gzip/gunzip命令,只能对文件进行压缩。只能压缩目录下的所有文件,压缩完成后,在目录下生成以.bz2为扩展名的压缩包。bunzip2其实是bzip2的符号链接,即软链接,因此压缩解压都可以通过bzip2实现。其格式如下:
bzip2命令的选项及其说明见表1-4。
表1-4 bzip2命令选项及含义
下面看几个使用例子。
将/opt目录下的etc.zip、var.zip和backup.zip进行压缩,设置压缩级别为最高,同时在压缩完毕后不删除原始文件,显示压缩过程的详细信息。
压缩完毕后,在/opt下就会生成相应的etc.zip.bz2、var.zip.bz2和backup.zip.bz2文件。
1.2.2 如何快速查找、搜索文件
1.强大的文件查找命令find
find命令用来在指定的路径下查找指定的文件。其格式如下:
具体的选项说明如下。
➢ path-name:find命令查找的目录路径,例如,可以用.表示当前目录,用/表示系统根目录。
➢ -options:find命令用来控制查找的方式。这里列出-options选项常见的几种格式,见表1-5。
表1-5 find命令选项及含义
➢ -print:将查找结果输出到标准输出。
➢ -exec:对查找出的符合条件的文件执行所给出的Linux命令,而不询问用户是否需要执行该命令。{}表示shell命令的选项即为所查找到的文件。命令的末尾必须以;结束。
注意:格式要正确,-exec命令{}\;,在}和\之间一定要有空格才行。
➢ -ok:对查找出的符合条件的文件执行所给出的Linux命令。与-exec不同的是,它会询问用户是否需要执行该命令。
下面列举find在运维中的一些常用例子。
1)在系统根目录下,查找文件类型为普通文件,属于ixdba用户的,2天以前的,并且不包含/usr/bin目录的文件名为main.c的文件,并将结果输出到屏幕。
2)对上例中查找的结果进行删除操作。
3)在系统根目录下查找不在/var/log和/usr/bin目录下的所有普通文件。
\ 表示引用,告诉shell不对后面的字符做特殊解释,而留给find命令去解释其意义。
注意:\(-path中,在(和-path之间是有空格的,同时/usr/bin\)在bin和\之间也是有空格的。
4)查找系统中所有大小为0的普通文件,并列出它们的完整路径。
5)查找系统/var/log目录中修改时间在7天以前的普通文件,然后以交互方式删除。
6)在当前目录及子目录下查找所有*.txt文件。
7)在用户自己的根目录下查找文件名以一个大写字母开头,紧接着是一个小写字母和两个数字,最后以.txt结尾的文件。
8)在/etc目录下查找文件属主为ixdba用户的文件。
2.给其他命令传递参数的过滤器命令xargs
Linux命令可以从两个地方读取要处理的内容:一个是通过命令行参数,一个是标准输入。例如,cat、grep就是这样的命令,举例如下:
这个命令组合中cat会输出name1的内容,而不是'iivey'字符串,如果name1文件不存在,则cat命令报告该文件不存在,而不会尝试从标准输入中读取;echo 'iivey'|会通过管道将echo的标准输出(也就是字符串'iivey')导入到cat的标准输入,也就是说此时cat的标准输入中是有内容的,其内容就是字符串'iivey',但是上面的命令中cat并不会从它的标准输入中读入要处理的内容。
标准输入其实是一个缓冲区,从标准输入中读取数据,实际上是从标准输入的缓冲区中读取的。基本上Linux的命令中很多命令的设计都是先从命令行中获取参数,然后从标准输入中读取,例如:
此时,cat会从其标准输入中读取内容并处理,也就是会输出 'iivey'字符串。echo命令将其标准输出的内容 'iivey' 通过管道定向到cat的标准输入中。其实还可以这样写这个命令:
这里直接在命令的最后指定-就表示从标准输入中读取数据,这个命令和上面那个命令是等价的。于是修改上面第一个命令为如下:
同时指定name1和-参数,此时cat程序不但会显示name1的内容,还会输出'iivey'字符串,也就是说此时cat可以接受第二个标准输入了。
这是cat命令的灵活用法,但并不是所有命令都跟cat一样,可以接受标准输入过来的数据,例如,kill、rm这些程序如果命令行参数中没有指定要处理的内容,则不会默认从标准输入中读取。所以类似
的写法是不能执行的。同样如下命令也是无法执行的。
这两个命令只接受命令行参数中指定的处理内容,不从标准输入中获取处理内容。但有时在实际的运维场景中,经常需要echo '516'|kill这样的效果,如ps-ef|grep 'abc'|kill,也就是筛选出符合某条件的进程PID,然后kill掉。这种需求是很常见的,那么应该怎样达到这样的效果呢?有以下几个解决办法。
1)通过kill ps-ef|grep 'ddd' 命令组合。这种形式是先得到PID,然后执行kill,实际上等同于拼接字符串得到的命令,其效果类似于kill$pid。
2)命令组合如下:
这个命令组合与第一种原理一样,只不过是利用for循环的方式,通过ps -aux | grep"some search"|awk '{print$2}'先拿到需要kill的所有PID,然后调用kill-9命令,每次处理一个,循环处理删除。
3)ps-ef|grep 'ddd'|xargs kill命令。下面重点介绍xargs命令。xargs命令可以通过管道接收字符串,并将接收到的字符串通过空格分割成许多参数(默认情况下是通过空格分割),然后将参数传递给其后面的命令,作为后面命令的命令行参数。有了xargs可以批量删除筛选出来的进程,非常简单。
下面来看看xargs如何使用,还是利用上面的那个例子:
这两个命令中,第1个输出的是字符串--help,也就是将echo的内容当作cat处理的文件内容,实际上就是echo命令的输出通过管道定向到cat的输入。然后cat从其标准输入中读取待处理的文本内容。所以这个命令的输出结果为--help。
第2个命令echo '--help' | xargs cat等价于cat --help命令组合。怎么理解呢?就是xargs将其接收的字符串--help做成cat的一个命令参数来运行cat命令。
下面通过几个案例来说明。首先看第1个例子,要批量重命名文件夹下的文件,可执行如下操作:
对上面操作过程解释如下。
➢ xargs-i:该选项在逻辑上用于接收传递的分批结果。如果不使用-i,则默认是将分割处理后的结果整体传递到命令的最尾部。但是有时候需要传递到多个位置,不使用-i就不知道传递到哪个位置了。例如,重命名备份的时候在每个传递过来的文件名加上扩展名.bak,这需要两个参数位。使用xargs -i时以大括号{}作为替换符号,传递的时候看到{}就将被结果替换。可以将{}放在任意需要传递的参数位上,如果多个地方使用{}就实现了多个传递。
➢ -t:该选项表示每次执行xargs后面的命令都会先在stderr上打印一遍命令的执行过程,然后才正式执行。类似的还是一个-p选项。使用-p选项是交互询问式的,只有每次询问的时候输入y(或yes)才会执行,直接按〈Enter〉键是不会执行的。使用-p或-t选项就可以根据xargs后命令的执行顺序进行推测,xargs是如何分段、分批以及如何传递的,通过它们有助于理解xargs的各种选项。
继续看第2个例子,要批量删除目录下扩展名为.txt的文件,可执行如下操作:
从这个操作中,可以看出-i、-t和-p参数的作用。
接着看第3个例子:默认情况下xargs将其标准输入中的内容以空白(包括空格、Tab、回车换行等)分割成多个之后当作命令行参数传递给其后面的命令并运行,可以使用-d参数指定分隔符,例如:
或者
这里通过参数-d指定了分隔符,所以等价于echo 11 22 33,相当于给echo传递了3个参数,分别是11、22、33。在第二个命令中,去掉了echo,得到的结果跟第一个结果一样,其实xargs命令后面不加命令的话,默认会自动调用echo命令。这可以通过如下方式验证:
加上-t参数后,可以清晰看出,xargs默认调用的是echo命令。
继续看第4个例子:来看看xargs的分批执行,也就是每次传递几个xargs生成的命令行参数给其后面的命令执行。如果xargs从标准输入中读入内容,然后以分隔符分割之后生成的命令行参数有10个,使用-n 3表示一次传递给xargs后面的命令是3个参数,因为一共有10个参数,所以要执行4次才能将参数用完,例如:
从输出可以看到,输入有10个参数,每次传递给echo命令3个参数,最后还剩一个,就直接传递一个参数,总共传递了4次。
再看最后一个例子:xargs和find同属于一个rpm包findutils,xargs原本就是为find而开发的,它们之间的配合应当是天衣无缝的。一般情况下它们随意结合,按正常方式进行即可。但是当删除文件时,特别需要将文件名含有空白字符的文件纳入考虑。看下面这个例子:
这里如果直接交给xargs rm-rf去删除,由于xargs处理后不指定分批选项时以空格分段,所以实际执行的是rm-rf./one space.log,这表示要删除的是当前目录下的one和当前目录下的space.log,这显然是错误的,要真正删除的只是one space.log一个文件而已。
有多种方法可以解决这个问题。思路是让找到的one space.log成为一个段,而不是两个段。这里给出了常见的两种方法。方法一如下:
这是通过常用的find的-print0选项使用\0来分隔,而不是\n分隔,再通过xargs-0来配对,保证one space.log的整体性。加上-print0参数表示find输出的每条结果后面加上 '\0'而不是换行,这样,由于-print0后one space.log的前后各有一个\0,但是中间没有文件名。所以上面命令可以执行成功。操作过程如下:
这里使用了xargs-0,其实xargs-0的行为和xargs-d基本是一样的,只是-d是指定分隔符,-0是指定固定的\0作为分隔符。因此,xargs-0就是特殊的xargs-d,它等价于xargs-d"\0"。
第二个方法是不在find上处理,而在xargs上处理,只要通过配合-i选项就能保证它的整体性。命令如下:
注意,最后的大括号必须有双引号。相比较而言,方法一的使用更广泛,而方法二则更具有通用性,对于非find命令(如ls)也可以进行处理。
1.2.3 如何对文件进行连接、合并、排序、去重
1.文件连接命令join
join命令用于将两个文件中指定列中内容相同的行连接起来。找出两个文件中指定列内容相同的行,并加以合并,再输出到标准输出设备。
常用的命令选项及含义见表1-6。
表1-6 join命令选项及含义
看一个例子。file1文件的内容:
file2文件的内容:
从file1.txt和file2.txt中可以看出,file1.txt中以:分割的第3列和file2.txt中以:分割的第3列内容相同,因此这两个文件可以合并整合在一起,操作如下:
可以看出,通过-t选项指定了分隔符后,输出的内容是将file1.txt文件的第3列和file2.txt文件的第3列进行整合的结果,两个文件合并后,相同的字段部分被移动到每行最前面了。
2.合并文件列命令paste
paste命令用于合并文件的列。它会把每个文件以列对列的方式,一列列地加以合并。paste比join简单很多,它其实就是直接将两个文件中相同的两行贴在一起,且中间以〈Tab〉键隔开。
例如,对上面的file1.txt和file2.txt进行paste合并,执行结果如下:
接着,再看一个组合例子:
这个例子的重点是-的使用,-代表标准输入,在这里会接收/etc/group的内容,因为通过cat/etc/group将此文件内容送到了标准输入,而-刚好接收了这个内容。因此,这个组合其实是3部分文件内容的合并,是/etc/passwd、/etc/shadow和/etc/group 3个文件内容合并的结果,而每行内容中通过默认的〈Tab〉键隔开。
3.文本内容排序命令sort
sort这个命令很好用,主要用来排序,基本使用格式为:
常用的命令选项及含义见表1-7。
表1-7 sort命令选项及含义
先看最简单的一个例子:
这是最简单的一个sort排序,没指定任何参数,所以默认以英文字母顺序进行排序,head表示默认显示前10行数据,要显示指定行数据,可以通过head-N实现。
继续看下面这个例子:
这个例子是通过指定分隔符':'对指定的列进行排序,k3表示以':'作为分隔符的第3列,也就是以第3列为准进行排序,由于第3列都是数字,所以还需要-n参数。
4.检查并删除文件中的重复行命令uniq
uniq主要用于检查及删除文本文件中重复出现的行,一般与sort命令结合使用,常用命令选项及含义见表1-8。
表1-8 uniq命令选项及含义
看下面的例子。这是ixdbafile1文件的内容:
可以看到有重复行,并且重复行都是相邻的,要删除重复行,uniq就派上用场了,操作如下:
可以看到,已经删除了重复行。如果要统计重复行出现的次数,加上-c参数即可,操作如下:
上面的ixdbafile1文件有些特殊,因为实际使用中,重复行不可能都是相邻在一起的,那继续来看另一个文件的内容:
这是一个重复行不相邻的文件,实际环境中,很多都是类似这样的文件,再通过uniq看看是否能够删除重复行。执行如下操作:
可以看到,文件原样输出了,也就是说uniq对这些重复行不相邻的内容无能为力。怎么办呢?sort可以解决。sort是排序用的,那就先把这个文件进行排序,这样,重复行就自动相邻了,操作如下:
经过sort排序后,重复行相邻了,接着通过管道后面接uniq命令即可过滤删除重复行了,操作如下:
果然,经过sort排序后,uniq又可以正常工作了,这也是为什么sort经常和uniq一起使用的原因了。
下面这个例子使用了uniq的-d参数,也就是显示重复行有哪些:
怎么样,通过几个简单例子发现uniq其实很简单吧?