Linux基础学习笔记(十二)——管道命令

前言

上一篇博客简述了一下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 731 14:33 servicesaa
-rw-r--r--. 1 root root 307200 731 14:33 servicesab
-rw-r--r--. 1 root root  55893 731 14:33 servicesac
## 将上述三个文件,合并为一个文件 使用数据流重定向即可完成
[root@localhost tmp]# cat services* >> servicesback
[root@localhost tmp]# ll
总用量 1312
-rw-r--r--. 1 root root 307200 731 14:33 servicesaa
-rw-r--r--. 1 root root 307200 731 14:33 servicesab
-rw-r--r--. 1 root root  55893 731 14:33 servicesac
-rw-r--r--. 1 root root 670293 731 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 -

总结

起于管道命令,基于管道命令总结了一堆结合管道命令的实例


版权声明:本文为liman65727原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。