管道命令
如果一些数据要经过几道手续之后才能得到我们想要的格式,应该如何来设置。这就是管道(pipe)命令的问题了,它使用 “|” 这个界定符号。而且管道命令与连续执行命令是不一样的。
假如我们想知道 /etc 下面有多少文件,那么可以利用 ls /etc 来查询,但是文件太多,我们不知道前面输出的内容是什么,此时我们就可以利用 less 来协助:
[root@mars ~]# ls -al /etc/ | less
这样的话, ls 命令的输出内容就能够被 less 读取,并且利用 less,我们可以很方便的查看。其实管道命令“ | ”仅能处理由前面一个命令传来的正确信息,也就是 Standard ouput 的信息,对于 Standard error 并没有处理能力。
- 管道命令仅会处理 standard output,对于standard error 会被会略
- 管道命令必须要能够接收来自前一个命令的数据成为 standard input 继续处理才行
所以,ls、cp、mv之类的命令就不能放在中间执行,因为他们不会接收来自前一个命令的 stdout。
选取命令:cut,grep
cut
范例1:将 PATH 变量取出,找出第五个路径
[root@mars ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
# 1 | 2 | 3 | 4 | 5
[root@mars ~]# echo $PATH | cut -d ':' -f 5
#如果上面的数字显示,我们是以“:”为分隔符,因此会出现 /root/bin
#如果要列出第 3 和第 5 就是这样的
[root@mars ~]# echo $PATH | cut -d ':' -f 3,5
当然,不仅仅是这样,我们完全还可以选取每一行的内容,比如:
[root@mars tmp]# export
declare -x HISTSIZE="3000"
declare -x HISTTIMEFORMAT="%F %T "
declare -x HOME="/root"
declare -x HOSTNAME="mars"
declare -x LANG="C"
...下面省略...
#我们可以发现,所有数据都是排列整齐输出的,如果我们不想要每行的“declare -x”,可以这样
[root@mars tmp]# export | cut -c 12-
HISTSIZE="3000"
HISTTIMEFORMAT="%F %T "
HOME="/root"
HOSTNAME="mars"
LANG="C"
...下面省略...
#我们还可以指定某个范围的值,比如 cut -c 12-20
grep
grep 是分析一行信息,若当中有我们需要的信息,就将该行拿出来,基本语法如下所示:
[root@mars ~]# grep [-acinv] [--color=auto] '查找字符串' filename
选项与参数:
-a:将 binary 文件以 text 文件的方式查找数据
-c:计算找到 '查找字符串' 的次数
-i:忽略大小写
-n:顺便输出行号
-v:反向选择,即显示出没有 '查找字符串' 的那一行
--color=auto:可以将找到的关键字部分加上颜色显示
范例1:将 last 中有出现 root 的那一行取出来
[root@mars ~]# last | grep 'root'
范例2:在 last 的输出信息中,只要有 root 就取出,并且进取第一列
[root@mars ~]# last | grep 'root'| cut -d ' ' -f1
范例3:取出 /etc/man_db.conf 内含 MANPATH 的那几行
[root@mars ~]# grep --color=auto 'MANPATH' /etc/man_db.conf
# MANDATORY_MANPATH manpath_element
# MANPATH_MAP path_element manpath_element
# every automatically generated MANPATH includes these fields
#MANDATORY_MANPATH /usr/src/pvm3/man
MANDATORY_MANPATH /usr/man
MANDATORY_MANPATH /usr/share/man
MANDATORY_MANPATH /usr/local/share/man
# set up PATH to MANPATH mapping
# *PATH* -> *MANPATH*
MANPATH_MAP /bin /usr/share/man
#找到的加上color的选项,找到都会用特殊颜色显示
排序命令:sort,wc,uniq
sort
排序的字符与语系的编码有关,因此如果你需要排序,建议设置 LANG=C 来统一。
[root@mars ~]# sort [-fbMnrtuk] [file or stdin]
选项与参数:
-f:忽略大小写
-b:忽略最前面的空格
-M:以月份来排序
-n:私用“纯数字”来排序
-r:反向排序
-u:就是uniq,相同的数据只出现一行代表
-t:分隔符,默认使用[Tab]来分隔
-k:以那个区间(field)来排序
范例1:排序个人账号记录
[root@mars ~]# cat /etc/passwd | sort
范例2:/etc/passwd 的记录都是以 : 分隔的,我想以第三列来排序
[root@mars ~]# cat /etc/passwd | sort -t ':' -k 3
#但是第三列排序的数字有点奇怪,因为它默认是文字排序,若需要数字
#这么写:cat /etc/passwd | sort -t ':' -k 3 -n
范例3:利用 last 将输出的数据仅选取账号,并排序
[root@mars ~]# last | cut -d ' ' -f1 | sort
uniq
如果排序完成了,想将重复的数据仅列出一个显示,可以怎么做?
[root@mars ~]# uniq [-ic]
选项与参数:
-i:忽略大小写
-c:进行计数
范例1:用 last 取出账号列,进行排序后仅取出一位,并计数
[root@mars ~]# last | cut -d ' ' -f1 | sort | uniq -c
1
1 reboot
96 root
1 wtmp
#第一行的空白字符和wtmp都是 last 的默认字符,可忽略
wc
如果我想知道 /etc/man_db.conf 这个文件里面有多少字?多少行?可以怎么做?
[root@mars ~]# wc [-lwm]
选项与参数:
-l:仅列出行
-w:仅列出多少字(英文单字)
-l:多少字符
范例1:查看 /etc/man_db.conf 里面多少相关字、行、字符
[root@mars ~]# cat /etc/man_db.conf | wc
131 723 5171
范例2:如何以一行命令取得这个月份登录系统的总人次
[root@mars ~]# last | grep [a-zA-Z] | grep -v 'wtmp' | wc -l
#由于last会输出空白行和 wtmp,我们利用grep取出,再计算行数
双向重定向:tee
tee 会同时将数据流送到文件和屏幕;而输出到屏幕的,其实就是 stdout,可以让下个命令继续处理
[root@mars ~]# tee [-a] file
选项与参数:
-a:以累加(append)的方式,将数据加入 file
[root@mars ~]# last | tee last.list | cut -d " " -f1
#让我们可以将 last 输出存一份到 last.list 文件中
[root@mars ~]# ls -l /etc/ | tee ~/homefile | more
#将 ls 数据存到 ~/homefile,同时屏幕输出
切割命令:split
如果有文件太大,导致一些便携设备无法复制,这个时候就可以用split
[root@mars ~]# split [-bl] file PREFIX
选项与参数:
-b:后面接想切割成的文件大小,单位:b,k,m等
-l:以行数来进行切割
PREFIX:代表前导符,可作为切割文件的前导文字
范例1:/tmp/etc.tar.bz2 有6.1M,若想分成 3M 一个文件怎么办
[root@mars /]# cd /tmp/; split -b 3m /tmp/etc.tar.bz2 etc
[root@mars tmp]# ll -k etc*
-rw-r--r-- 1 root root 6341666 Mar 13 16:35 etc.tar.bz2
-rw-r--r-- 1 root root 3145728 Mar 13 16:37 etcaa
-rw-r--r-- 1 root root 3145728 Mar 13 16:37 etcab
-rw-r--r-- 1 root root 50210 Mar 13 16:37 etcac
#我们只要写上前导文字,小文件就会以
#xxxaa,xxxab,xxxac等方式来新建小文件
范例2:如何合并?文件名为 etcback
[root@mars tmp]# cat etca* >> etcback
#直接数据流重定向
关于减号 - 的用途
在管道命令中,经常会使用前一个命令的 stdout 作为后面的 stdin,某些时候,我们可以用减号“ - ”来代替:
[root@mars tmp]# tar -cvf - /home | tar -xvf -
我们将/home 的文件打包,但是不是记录到文件,而是传送到 stdout,经过管道,传给后面的tar -xvf -,因此我们就不要文件了,这是很常见的。
#将ls -al 的信息输出,每10个记录一个文件
[root@mars tmp]# ls -al / | split -l 10 - lstmp
[root@mars tmp]# wc -l lstmpa*
10 lstmpaa
10 lstmpab
6 lstmpac
26 total