文章目录
前言
上一篇博客简述了一下Linux中的输入输出重定向,这篇博客总结一下Linux中的管道命令,为后面的文件格式化,shell学习做一个基础,对应《鸟哥的Linux私房菜》第十章10.6的内容
管道命令
其实管道命令,就是使用|
这个界定符号,这个命令默认仅能处理经由前一个指令传过来的正确信息,也就是上一篇博客中提到的standard output信息,对于standard error 标准错误信息,默认是没法处理的。
如果想要管道命令之后的某个命令,可以处理标准错误输出,可以将标准输出和标准错误输出均重定向到一处,这个在上一篇博客中有介绍,这里不做说明了。
下面总结的命令,是在管道命令的基础上进行一些数据处理
cut命令
主要用于数据的截取,从列的角度进行数据截取,上一篇博客中的grep命令是从行的角度过滤数据。
实例
##将export输出的结果,从第12个字符开启截取,一直截取到末尾,输出结果
[root@localhost shell-learn]# export | cut -c 12-
CLASSPATH=".:%JAVA_HOME%/lib/dt.jar:%JAVA_HOME%/lib/tools.jar"
HISTCONTROL="ignoredups"
HISTSIZE="1000"
HOME="/root"
HOSTNAME="localhost.localdomain"
JAVA_HOME="/usr/local/software/java/jdk1.8.0_191"
LANG="zh_CN.UTF-8"
LESSOPEN="||/usr/bin/lesspipe.sh %s"
LOGNAME="root"
###...以下输出结果省略
# 用如下命令,可以达到同等效果
[root@localhost shell-learn]# export | cut -d ' ' -f 3
CLASSPATH=".:%JAVA_HOME%/lib/dt.jar:%JAVA_HOME%/lib/tools.jar"
HISTCONTROL="ignoredups"
HISTSIZE="1000"
HOME="/root"
###...以下输出结果省略
##从last命令的输出结果中,截取登录的用户名
[root@localhost shell-learn]# last | cut -d ' ' -f 1
reboot
root
reboot
root
###...以下输出结果省略
sort,wc,uniq命令
sort命令
sort可以帮我们进行数据的排序,而且可以根据不同的数据形态来排序
如果要详细探讨每一个命令属性,这个就有点麻烦了,《鸟哥的Linux私房菜》也只介绍了简单的几个实例
## 读取个人账号信息数据,并排序,默认按第一个数据来排序
[root@localhost shell-learn]# cat /etc/passwd | sort
adm:x:3:4:adm:/var/adm:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
esuser:x:1001:1001::/home/esuser:/bin/bash
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
halt:x:7:0:halt:/sbin:/sbin/halt
###...以下输出结果省略
##读取个人账号信息数据,并以第三列数据进行排序
### -t指定分割符,-k指定分割之后的排序字段
[root@localhost shell-learn]# cat /etc/passwd | sort -t ':' -k 3
root:x:0:0:root:/root:/bin/bash
esuser:x:1001:1001::/home/esuser:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
###...以下输出结果省略
## 可以看到上面的结果11 排在1001之后,这没按照数字排序,如果按照数字排序,需要指定-n选项
[root@localhost shell-learn]# cat /etc/passwd | sort -t ':' -k 3 -n
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
###...以下输出结果省略
## 通过last读取登录数据,按照列切分之后,得到登录账号数据,并排序
[root@localhost shell-learn]# last | cut -d ' ' -f1 | sort
reboot
###...以下输出结果省略
uniq命令
类似SQL语句中的distinct,这里是对排序之后的结果进行去重
实例
## 通过last命令读取登录信息,并根据空格进行分割,然后读取登录账号,排序,去重。
[root@localhost shell-learn]# last | cut -d ' ' -f1 | sort | uniq
##输出结果
reboot
root
wtmp
## 通过last命令读取登录信息,并根据空格进行分割,然后读取登录账号,排序,去重,并统计登录次数,类似SQL中的count。
[root@localhost shell-learn]# last | cut -d ' ' -f1 | sort | uniq -c
1
65 reboot
87 root
1 wtmp
wc命令
wc命令用于统计文件里头多少字符,多少行,多少字符信息。
实例
# 读取man_db.conf中的数据,并进行字符统计
# 输出的三个结果中,分别表示[行,字数,字符数]
[root@localhost shell-learn]# cat /etc/man_db.conf | wc
131 723 5171
# 读取last命令中登入系统的总人数
##这里通过grep -v命令,去除了很多无用的登录记录信息
[root@localhost shell-learn]# last | grep [a-zA-Z] |grep -v 'wtmp' | grep -v 'reboot' | \
> grep -v 'unknown' | wc -l
87
# 读取当前系统中有多少个账户
[root@localhost shell-learn]# cat /etc/passwd | wc -l
21
双向重定向——tee命令
之前我们在利用重定向命令输出的时候,将数据流重定向到某个文件之后,屏幕的标准输出就木有了,tee命令可以将数据流分送到文件和屏幕
实例
#使用tee命令之后,可以将标准输出备份到文件的同时,也不影响数据流后续的标准输出
## 该命令执行完成之后,last.txt中会存有一份last命令的标准输出,后面的cut也能得到正常结果
[root@localhost shell-learn]# last | tee last.txt | cut -d ' ' -f1
字符替换命令
除了使用dos2unix和unix2dox来进行换行符的转换之外,linux还提供了其他字符转换的命令
tr命令
用来删除信息中的一些文件或者进行文字替换
实例
# 将last命令的输出结果中,小写字母转成大写字母
[root@localhost shell-learn]# last | tr '[a-z]' '[A-Z]'
ROOT PTS/0 192.168.0.103 SUN JUL 31 09:53 STILL LOGGED IN
ROOT TTY1 SUN JUL 31 09:53 STILL LOGGED IN
REBOOT SYSTEM BOOT 3.10.0-1160.EL7. SUN JUL 31 09:52 - 11:31 (01:38)
###...以下输出结果省略
## 将cat /etc/passwd命令的输出结果中的冒号删除
[root@localhost shell-learn]# cat /etc/passwd | tr -d ':'
rootx00root/root/bin/bash
binx11bin/bin/sbin/nologin
daemonx22daemon/sbin/sbin/nologin
###...以下输出结果省略
col命令
这个命令用来简单的将tab键替换成空格
实例
#cat -A显示所有特殊字符,col -x 将tab替换成空格,最后的more命令显示的内容没有^I字符
[root@localhost shell-learn]# cat /etc/man_db.conf | col -x | cat -A | more
join命令
类似SQL中的join,如果两个文件中的数据列相同,则通过join命令只输出一列
实例
# 通过head命令查看,/etc/passwd和/etc/shadow两个文件中的第一列是相同的
[root@localhost shell-learn]# head -n 3 /etc/passwd /etc/shadow
==> /etc/passwd <==
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
==> /etc/shadow <==
root:$6$FI.UzpVEoa1js0tM$j2khNaltnlIWqz7/aXd7scHOIrwJiVxIh.df9Da1gMQYdxBXL1O6odGDZNhjfMSfxb1u39jGXQ6/.o1f0duRS0::0:99999:7:::
bin:*:18353:0:99999:7:::
daemon:*:18353:0:99999:7:::
#通过join命令查询之后,第一列只显示一次
[root@localhost shell-learn]# join -t ':' /etc/passwd /etc/shadow | head -n 3
root:x:0:0:root:/root:/bin/bash:$6$FI.UzpVEoa1js0tM$j2khNaltnlIWqz7/aXd7scHOIrwJiVxIh.df9Da1gMQYdxBXL1O6odGDZNhjfMSfxb1u39jGXQ6/.o1f0duRS0::0:99999:7:::
bin:x:1:1:bin:/bin:/sbin/nologin:*:18353:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin:*:18353:0:99999:7:::
# /etc/passwd中的第四列和/etc/group文件中的第三列内容是一致的
[root@localhost shell-learn]# head -n 3 /etc/passwd /etc/group
==> /etc/passwd <==
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
==> /etc/group <==
root:x:0:
bin:x:1:
daemon:x:2:
# 通过join指定匹配的列,-1指定第一个文件要匹配的列,-2指定第二个文件要匹配的列
[root@localhost shell-learn]# join -t ':' -1 4 /etc/passwd -2 3 /etc/group | head -n 3
0:root:x:0:root:/root:/bin/bash:root:x:
1:bin:x:1:bin:/bin:/sbin/nologin:bin:x:
2:daemon:x:2:daemon:/sbin:/sbin/nologin:daemon:x:
需要特别注意的是,在使用join之前,数据最好已经经过排序
paste命令
paste命令比join命令要简单,paste是直接将两行数据贴在一起,中间tab键隔开,不管这两行数据中是否有可匹配的字段
实例
## 将/etc/passwd /etc/shadow文件同一行拼接在一起,并显示前三行
[root@localhost shell-learn]# paste /etc/passwd /etc/shadow | head -n 3
root:x:0:0:root:/root:/bin/bash root:$6$FI.UzpVEoa1js0tM$j2khNaltnlIWqz7/aXd7scHOIrwJiVxIh.df9Da1gMQYdxBXL1O6odGDZNhjfMSfxb1u39jGXQ6/.o1f0duRS0::0:99999:7:::
bin:x:1:1:bin:/bin:/sbin/nologin bin:*:18353:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin daemon:*:18353:0:99999:7:::
expand命令
将tab键的字符转成空格符
实例
#从man_db.conf文件中,以MANPATH开头的数据
[root@localhost shell-learn]# grep '^MANPATH' /etc/man_db.conf | head -n 3
MANPATH_MAP /bin /usr/share/man
MANPATH_MAP /usr/bin /usr/share/man
MANPATH_MAP /sbin /usr/share/man
##tab键的符号,在cat -A之后,通过^I显示出来
[root@localhost shell-learn]# grep '^MANPATH' /etc/man_db.conf | head -n 3 | cat -A
MANPATH_MAP^I/bin^I^I^I/usr/share/man$
MANPATH_MAP^I/usr/bin^I^I/usr/share/man$
MANPATH_MAP^I/sbin^I^I^I/usr/share/man$
## 这里设定的是6个字符代表一个tab符号
[root@localhost shell-learn]# grep '^MANPATH' /etc/man_db.conf | head -n 3 | expand -t 6 | cat -A
MANPATH_MAP /bin /usr/share/man$
MANPATH_MAP /usr/bin /usr/share/man$
MANPATH_MAP /sbin /usr/share/man$
文件拆分命令
split命令是linux中的文件拆分命令
实例
[root@localhost shell-learn]# cd /tmp
##指定以300k的大小进行文件拆分,前缀为services
[root@localhost tmp]# split -b 300k /etc/services services
[root@localhost tmp]# ll
总用量 656
-rw-r--r--. 1 root root 307200 7月 31 14:33 servicesaa
-rw-r--r--. 1 root root 307200 7月 31 14:33 servicesab
-rw-r--r--. 1 root root 55893 7月 31 14:33 servicesac
## 将上述三个文件,合并为一个文件 使用数据流重定向即可完成
[root@localhost tmp]# cat services* >> servicesback
[root@localhost tmp]# ll
总用量 1312
-rw-r--r--. 1 root root 307200 7月 31 14:33 servicesaa
-rw-r--r--. 1 root root 307200 7月 31 14:33 servicesab
-rw-r--r--. 1 root root 55893 7月 31 14:33 servicesac
-rw-r--r--. 1 root root 670293 7月 31 14:36 servicesback
## 将 ls -al /的输出信息,每10行记录生成一个文件
[root@localhost tmp]# ls -al / | split -l 10 - lssplitfile
[root@localhost tmp]# wc -l lssplitfile*
10 lssplitfileaa
10 lssplitfileab
5 lssplitfileac
25 总用量
参数替换
xargs是管道命令中,控制传递个下一个命令的参数个数
实例
#正常的id命令可以显示用户组别等详细信息
[root@localhost tmp]# id
uid=0(root) gid=0(root) 组=0(root) 环境=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[root@localhost tmp]# id root
uid=0(root) gid=0(root) 组=0(root)
## 可以通过截取/etc/passwd文件得到用户信息
[root@localhost tmp]# cut -d ':' -f 1 /etc/passwd | head -n 3
root
bin
daemon
# 是否可以直接通过管道,将这里两个命令结合,达到输出所有用户组别信息的目的?
##取出了三个,但是只有一个,因为前面的命令输出了三个用户,但是id只能接受一个参数,下述指令相当于只执行了id
[root@localhost tmp]# cut -d ':' -f 1 /etc/passwd | head -n 3 | id
uid=0(root) gid=0(root) 组=0(root) 环境=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
##换一种姿势也不行
[root@localhost tmp]# id $(cut -d ':' -f 1 /etc/passwd | head -n 3)
id: 额外的操作数 "bin"
Try 'id --help' for more information.
##通过xargs指示传递给下一个命令的那参数,一个一个的给。可以得到正确结果
[root@localhost tmp]# cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -n 1 id
uid=0(root) gid=0(root) 组=0(root)
uid=1(bin) gid=1(bin) 组=1(bin)
uid=2(daemon) gid=2(daemon) 组=2(daemon)
#加上 -p 选项,每次都会询问用户是否确认执行
[root@localhost tmp]# cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -p -n 1 id
id root ?...y
uid=0(root) gid=0(root) 组=0(root)
id bin ?...y
uid=1(bin) gid=1(bin) 组=1(bin)
id daemon ?...y
uid=2(daemon) gid=2(daemon) 组=2(daemon)
#将所有/etc/passwd内的账号都以id进行查阅,但差到sync就结束
[root@localhost tmp]# cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -e'sync' -n 1 id
uid=0(root) gid=0(root) 组=0(root)
uid=1(bin) gid=1(bin) 组=1(bin)
uid=2(daemon) gid=2(daemon) 组=2(daemon)
xargs是一个比较好用的工具,可以将原来本身不支持管道命令的操作一起级联起来。
关于-
在管道命令中,有时候会出现-
这是因为,有时候管道命令会使用到前一个指令的标准输出作为本地的输入,但是这个时候用文件作为中转有些不方便,因此 - 其实就代表命令的标砖输出。
# 例如:我们要打包一个文件夹/var/log到当前目录下通常分为两步
tar -cvf log.tar /var/log/
zip -r log.tar.zip log.tar
rm -rf log.tar
# 写成一条语句
tar -cvf log.tar /var/log/ && zip -r log.tar.zip log.tar && rm -rf log.tar
## 可以看到第一条语句的log.tar就是第二条语句的输入,可以用 - 来取代这个输入
tar -cvf – /var/log | zip -r log.zip -
总结
起于管道命令,基于管道命令总结了一堆结合管道命令的实例