管道(pipe)

回到顶部

管道(pipe)命令是使用管道线符号|分割的命令。一条命令的输入可能来自标准输入或者文件,也可以来自另一条命令的输入。 同理,一条命令的输出可以输出到标准(错误)输出或者文件,也可以输出到另一条命令。管道就是将命令的标准输入重定向到另一条命令的标准输出, 命令的标准输出重定向到另一条命令的标准输入。这里要注意管道并不处理标准错误输出。管道线符号和重定向符号都属于数据重定向符号。
到目前为止,可以连接两条命令的符号有:
1.管道线;
2.重定向;
3.连续执行命令分号;
4.&&和||;
注意管掉线|和其他几个符号的区别。
我们先举一个简单的管道线命令,在用ls命令查看/etc目录下的文件的时候,由于/etc目录下的文件过多,超过了一屏, 导致前面的内容来不及看到。这时我们就可以将ls的输出通过管道线重定向到less命令,再由less命令输出到屏幕:

              [peter@study ~]$ ls -al /etc | less
            
这样ls命令的输出就被less命令读取,利用less的功能,就可以前后翻页查看相关的信息了! 管道命令|仅能处理命令的标准输入standard input和标准输出standard output, 对于standard error并没有直接处理的能力。管道命令示意如下图所示:
linux管道命令示意图 图 管道命令的处理示意图
通常重定向符号后面接的是文件,而管道后面接的必须是命令,而且这个命令必须能够接受standard input, 这样的命令才可以称为管道命令,例如less, more, head, tail等都是可以接受standard input的管道命令。 至于ls, cp, mv等就不是管道命令了!因为ls, cp, mv并不会接受来自stdin的数据。 综上所述,管道命令主要有两个需要注意的地方:
管道命令仅处理standard output,对于standard error output会予以忽略;
管道命令必须要能够接受来自前一个命令的数据成为standard input继续处理才行。
其实我们也可以将标准错误输出通过管道命令输入给管道命令, 只不过需要先将标准错误输出用重定向符号重定向到标准输出,即在管道线之前加入2>&1
下面介绍一些常用的管道命令。

常见的管道命令

回到顶部

常用管道命令
1.linux cut命令
2.linux grep命令
3.linux tee命令
4.linux wc命令
5.linux join命令
6.linux col命令
7.linux expand命令
8.linux paste命令
9.linux sort命令
10.linux split命令
11.linux tr命令
12.linux uniq命令
13.linux xargs命令

下面介绍一些常用的管道命令。

提取命令: cut, grep

回到顶部

提取命令就是将一段数据经过分析后,取出我们想要的数据信息。大部分提取命令都是以行为单位进程信息提取。
cut就是切的意思,cut命令以行为单位将一行信息中的某一段切取出来。 cut常用命令格式如下所示:

              [peter@study ~]$ cut -d'分隔字符' -f fields #用于有特定分隔字符
              [peter@study ~]$ cut -c 字符区间 #用于排列整齐的信息
            
选项与参数:
-d :后面接分隔字符。与-f一起使用;
-f :依据-d的分隔字符将一段信息分区成为数段,用-f取出第几段的意思;
-c :以字符(characters)的单位取出固定字符区间;
找出PATH环境变量中的第五个路径:
              [peter@study ~]$ echo ${PATH}
              /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
              [peter@study ~]$ echo ${PATH} | cut -d ':' -f 5
              /sbin
            
上面就是将echo ${PATH}输出内容以:号分割,取出第五段内容。 如果想要列出第3与第5呢:
              [peter@study ~]$ echo ${PATH} | cut -d ':' -f 3,5
              /usr/sbin:/sbin
            
将export输出的信息,取得第12字符以后的所有字符串:
              [peter@study ~]$ export
              declare -x CINNAMON_SLOWDOWN_FACTOR="0.0001"
              declare -x CINNAMON_SOFTWARE_RENDERING="1"
              declare -x CINNAMON_VERSION="4.0.10"
              declare -x COLORTERM="truecolor"
              declare -x DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
              declare -x DEFAULTS_PATH="/usr/share/gconf/cinnamon.default.path"
              declare -x DESKTOP_SESSION="cinnamon"
              ...省略...
            
可以看到上面的的每一行最前面都是declare -x,可以不需要declare -x:
              [peter@study ~]$ export | cut -c 12-
              CINNAMON_SLOWDOWN_FACTOR="0.0001"
              CINNAMON_SOFTWARE_RENDERING="1"
              CINNAMON_VERSION="4.0.10"
              COLORTERM="truecolor"
              DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/1000/bus"
              DEFAULTS_PATH="/usr/share/gconf/cinnamon.default.path"
              DESKTOP_SESSION="cinnamon"
              ...省略...
            
用 -c 可以处理比较具有格式的输出数据!
可以指定某个范围的值,例如第 12-20 的字符,就是 cut -c 12-20 等等!
用last命令列出登录用户信息,仅查看用户名:
              [peter@study ~]$ last
              root pts/1 192.168.201.101 Sat Feb 7 12:35   still logged in
              root pts/1 192.168.201.101 Fri Feb 6 12:13 - 18:46 (06:33)
              root pts/1 192.168.201.254 Thu Feb 5 22:37 - 23:53 (01:16)
            
last命令输出账号/终端机/来源/日期时间的登录数据。
              [peter@study ~]$ last | cut -d ' ' -f 1
            
由输出的结果我们可以发现第一个空白分隔的字段代表账号,所以使用如上命令。 但是因为root pts/1之间有好几个空格,所以,如果要找出pts/1其实不能以 cut -d ' ' -f 1,2。
cut主要的用途在于将同一行里面的数据,以某些字符作为分隔符进行分解切割,以取得我们所需要的数 据。最常使用在分析一些数据或文字数据的时候!尤其是在分析log文件的时候! 不过,cut在处理多空格相连的数据时,可能会比较吃力一点,所以某些时刻可能会使用awk来取代!

提取命令: grep

回到顶部

cut命令是提取一行中的某一段内容,而grep则是提取符合条件的一整行信息。 grep会分析一行信息, 如果该行有我们所需要的信息,就将整行信息提取出来:

              [peter@study ~]$ grep [-acinv] [--color=auto] '搜寻字符串' filename
            
选项与参数:
-a :将binary文件以text文件的方式搜寻数据;
-c :计算找到'搜寻字符串'的次数;
-i :忽略大小写的不同,大小写视为相同;
-n :顺便输出行号;
-v :反向选择,亦即显示出没有'搜寻字符串'内容的那一行;
--color=auto :可以将找到的关键词部分加上颜色显示!
将last命令的输出中,输出带有root的行:
              [peter@study ~]$ last | grep 'root'
            
与上例相反,取出没有root的行:
              [peter@study ~]$ last | grep -v 'root'
            
在last的输出信息中,取出含有root的行,并且每行只取第一栏:
              [peter@study ~]$ last | grep 'root' | cut -d ' ' -f 1
            
# 在取出 root 之后,利用上个命令 cut 的处理,就能够仅取得第一栏啰!
取出/etc/manpath.conf文件中含有MANPATH的行:
              [peter@study ~]$ grep --color=auto 'MANPATH' /etc/manpath.config
              ...省略...
              MANPATH_MAP	/bin			/usr/share/man
              MANPATH_MAP	/usr/bin		/usr/share/man
              MANPATH_MAP	/sbin			/usr/share/man
              ...省略...
            
加上--color=auto选项,grep会将找到的关键词用特殊颜色显示! CentOS 7当中,alias grep='grep --color=auto',grep其实是grep --color=auto的命令别名。 默认就已经加上--color=auto了! grep可以解析一行文字,取得关键词,若该行有存在关键词,就会整行列出来! grep是个非常实用的命令!结合正则表达式,可以提取复杂的数据。关于正则表达式,我们稍后介绍。

双向重定向: tee

回到顶部

双向重定向: tee
输出重定向>或>>是将命令的标准(错误)输出重新定向到文件或者设备,输出重定向后,数据不会显示在屏幕上。 但是有时候,我们即想让数据输出到指定的文件或者设备,同时也希望数据还可以输出到屏幕。
tee可以同时将数据流输出到文件和标准输出,tee数据流示意图如下所示:
tee数据流示意图 图 tee数据流示意图

              [peter@study ~]$ tee [-a] file
            
-a选项以累加(append)的方式,将数据写入file文件中!
tee可以让standard output转存一份到文件内并将同样的数据继续送到屏幕去处理! 这样除了可以让我们同时分析一份数据并记录下来之外,还可以作为处理一份数据的中间暂存盘记录之用!
将last的输出存一份到last.list 文件中;
              [peter@study ~]$ last | tee last.list | cut -d " " -f1
            
将ls的数据存一份到~/homefile,同时屏幕也有输出信息:
              [peter@study ~]$ ls -l /home | tee ~/homefile | more
            
tee后接的文件会被覆盖,加上-a选项则能将信息累加:
              [peter@study ~]$ ls -l / | tee -a ~/homefile | more
            

linux wc命令

回到顶部

wc命令用于统计输入的字数、行数和字符数。

              [peter@study ~]$ wc [-lwm]
            
选项与参数:
-l :仅列出行;
-w :仅列出多少字(英文单字);
-m :多少字符;
统计/etc/manpath.config文件的行数、字数和字符数:
              [peter@study ~]$ cat /etc/manpath.config | wc
                  131     715    5174
            
输出的三个数字分别代表行数、字数和字符数
使用 last 可以输出登入者,但是 last 最后两行并非账号内容,该如何以一行命令串取得登入系统的总人次?
              [peter@study ~]$ last | grep [a-zA-Z] | grep -v 'wtmp' | grep -v 'reboot' | \
              > grep -v 'unknown' |wc -l
            
由于 last 会输出空白行, wtmp, unknown, reboot 等无关账号登入的信息, 因此利用grep取出非空白行,以及去除上述关键词那几行,再计算行数,就可以了!
打印出账号文件中有多少个账号:
              [peter@study ~]$ cat /etc/passwd | wc -l
            
因为/etc/passwd文件中每一行代表一个用户! 所以只需要统计行数就可以知道有多少的账号了! 而如果要计算一个文件里头有多少个字符时,就使用 wc -m 这个选项吧!

join处理两个文件之间的数据,主要是在处理两个文件当中,有相同数据的那一行,才将他加join在一起

              [peter@study ~]$ join [-ti12] file1 file2
            
选项与参数:
-t :join 默认以空格符分隔数据,并且比对『第一个字段』的数据,如果两个文件相同,则将两笔数据联成一行,且第一个字段放在第一个!
-i :忽略大小写的差异;
-1 :这个是数字的1 ,代表第一个文件要用那个字段来分析的意思;
-2 :代表第二个文件要用那个字段来分析的意思。
用 root 的身份,将 /etc/passwd 与 /etc/shadow 相关数据整合成一栏
              [root@initroot ~]# sudo head -n 3 /etc/passwd /etc/shadow
              ==> /etc/passwd <==
              root:x:0:0:root:/root:/bin/bash
              daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
              bin:x:2:2:bin:/bin:/usr/sbin/nologin

              ==> /etc/shadow <==
              root:$6$iWZdx1dL$UmMmRTYcPPYmIOLphHouLkfqbsy2k4uyLnekclB4LnBP9ksLDGCqZ5kTS/uxsl7D4umb1/.RrEJF/Xw0lDlDu/:18268:0:99999:7:::
              daemon:*:17882:0:99999:7:::
              bin:*:17882:0:99999:7:::

            
从上面的输出可以看出这两个文件的最左边字段都是相同账号!且以 : 分隔
              [root@initroot ~]# join -t ':' /etc/passwd /etc/shadow | head -n 3
              root:x:0:0:root:/root:/bin/bash:$6$iWZdx1dL$UmMmRTYcPPYmIOLphHouLkfqbsy2k4uyLnekclB4LnBP9ksLDGCqZ5kTS/uxsl7D4umb1/.RrEJF/Xw0lDlDu/:18268:0:99999:7:::
              daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin:*:17882:0:99999:7:::
              bin:x:2:2:bin:/bin:/usr/sbin/nologin:*:17882:0:99999:7:::
            
这样我们就可以将两个文件第一字段相同者整合成一行!第二个文件的相同字段并不会显示(因为已经在最左边的字段出现了啊!)
我们知道/etc/passwd第四个字段是GID ,那个GID记录在/etc/group文件中的第三个字段,请问如何将两个文件整合?
              [root@initroot ~]# head -n 3 /etc/passwd /etc/group
              ==> /etc/passwd <==
              root:x:0:0:root:/root:/bin/bash
              daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
              bin:x:2:2:bin:/bin:/usr/sbin/nologin

              ==> /etc/group <==
              root:x:0:peter
              daemon:x:1:
              bin:x:2:

            
从上面可以看到,确实有相同的部分喔!赶紧来整合一下!
              [root@initroot ~]# join -t ':' -1 4 /etc/passwd -2 3
                /etc/group | head -n 3
              join: /etc/passwd:6: is not sorted: games:x:5:60:games:/usr/games:/usr/sbin/nologin
              join: /etc/group:11: is not sorted: uucp:x:10:
              0:root:x:0:root:/root:/bin/bash:root:x:peter
              1:daemon:x:1:daemon:/usr/sbin:/usr/sbin/nologin:daemon:x:
              2:bin:x:2:bin:/bin:/usr/sbin/nologin:bin:x:
            
# 同样的,相同的字段部分被移动到最前面了!所以第二个文件的内容就没再显示。
# 请读者们配合上述显示两个文件的实际内容来比对!
这个 join 在处理两个相关的数据文件时,就真的是很有帮助的啦! 例如上面的案例当中, 我的/etc/passwd, /etc/shadow, /etc/group 都是有相关性的, 其中 /etc/passwd, /etc/shadow 以账号为相关性,
至于/etc/passwd, /etc/group则以所谓的GID(账号的数字定义) 来作为他的相关性。 根据这个相关性,我们可以将有关系的资料放置在一起!这在处理数据可是相当有帮助的! 但是上面的例子有点难,希望您可以静下心好好的看一看原因喔!此外,需要特别注意的是,在使用 join 之前,你所需要处理的文件应该要事先经过排序 (sort) 处理!
否则有些比对的项目会被略过呢!特别注意了!

              [peter@study ~]$ col [-xb]
            
选项与参数:
-x:将tab键转换成对等的空格键
利用 cat -A 显示出所有特殊按键,最后以col将[tab]转成空白:
              [peter@study ~]$ cat -A /etc/man_db.conf
              #此时会看到很多 ^I 的符号,那就是 tab
              [peter@study ~]$ cat /etc/man_db.conf | col -x | cat -A | more
            
这样tab键会被取代成为空格键,输出就美观多了!
虽然 col 有他特殊的用途,不过,很多时候,他可以用来简单的处理将tab按键取代成为空格键!
例如上面的例子当中,如果使用 cat -A 则 [tab] 会以 ^I 来表示。 但经过 col -x 的处理,则会将 [tab]取代成为对等的空格键!

expand

回到顶部

expand将tab键转成空格键:

              [peter@study ~]$ expand [-t] file
            
选项与参数: -t:后面可以接数字。一般来说,一个 tab 按键可以用 8 个空格键取代。 我们也可以自行定义一个 [tab] 按键代表多少个字符呢!
将 /etc/man_db.conf 内行首为 MANPATH 的字样就取出;仅取前三行;
              [peter@study ~]$ grep '^MANPATH' /etc/manpath.config | head -n 3
              MANPATH_MAP	/bin			/usr/share/man
              MANPATH_MAP	/usr/bin		/usr/share/man
              MANPATH_MAP	/sbin			/usr/share/man
            
行首的代表标志为^,这个我们留待下节介绍!先有概念即可!
用cat将所有的符号都列出来:
              [peter@study ~]$ grep '^MANPATH' /etc/manpath.config | 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$
            
tab键被cat -A显示为^I
将tab键设定成6个字符:
              [peter@study ~]$ grep '^MANPATH' /etc/manpath.config | 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$
            
上面是以6个字符来代表一个tab的长度,所以MAN...到/usr之间会隔12(两个tab)个字符!如果tab改成9,情况就又不同了!
expand自动将tab转成空格键,所以,以上面的例子来说, 使用 cat -A 就会查不到 ^I 的字符。 此外,因为tab最大的功能就是格式排列整齐! 我们转成空格键后,这个空格键也会依据我们自己的定义来增加大小~ 所以,并不是一个^I就会换成8个空白喔! 这个地方要特别注意的哩! 此外,您也可以参考一下unexpand这个将空白转成tab的命令功能!

paste

回到顶部

paste就要比join 简单多了!相对于join 必须要比对两个文件的数据相关性, paste直接将两行贴在一起,且中间以tab键隔开!简单的使用方法:

              [peter@study ~]$ paste [-d] file1 file2
            
选项与参数:
-d :后面可以接分隔字符。预设是以 [tab] 来分隔的!
- :如果 file 部分写成 - ,表示来自 standard input 的资料的意思。
用 root 身份,将 /etc/passwd 与 /etc/shadow 同一行贴在一起:
              [root@initroot ~]# paste /etc/passwd /etc/shadow
              root:x:0:0:root:/root:/bin/bash	root:$6$iWZdx1dL$UmMmRTYcPPYmIOLphHouLkfqbsy2k4uyLnekclB4LnBP9ksLDGCqZ5kTS/uxsl7D4umb1/.RrEJF/Xw0lDlDu/:18268:0:99999:7:::
              daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin	daemon:*:17882:0:99999:7:::
              bin:x:2:2:bin:/bin:/usr/sbin/nologin	bin:*:17882:0:99999:7:::
              sys:x:3:3:sys:/dev:/usr/sbin/nologin	sys:*:17882:0:99999:7:::
              sync:x:4:65534:sync:/bin:/bin/sync	sync:*:17882:0:99999:7:::
              ...省略...
            
注意同一行中间以tab键隔开!
先将 /etc/group 读出(用 cat),然后与范例一贴上一起!且仅取出前三行
              [root@initroot ~]# cat /etc/group | paste /etc/passwd /etc/shadow - | head -n 3
              root:x:0:0:root:/root:/bin/bash	root:$6$iWZdx1dL$UmMmRTYcPPYmIOLphHouLkfqbsy2k4uyLnekclB4LnBP9ksLDGCqZ5kTS/uxsl7D4umb1/.RrEJF/Xw0lDlDu/:18268:0:99999:7:::	root:x:0:peter
              daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin	daemon:*:17882:0:99999:7:::	daemon:x:1:
              bin:x:2:2:bin:/bin:/usr/sbin/nologin	bin:*:17882:0:99999:7:::	bin:x:2:
            
重点在那个 - 的使用!那玩意儿常常代表 stdin 喔!

排序命令: sort, wc, uniq

回到顶部

很多时候,我们都会去计算一次数据里头的相同型态的数据总数,举例来说, 使用 last 可以查得系 统上面有登入主机者的身份。那么我可以针对每个使用者查出他们的总登入次数吗? 此时就得要排 序与计算之类的命令来辅助了!底下我们介绍几个好用的排序与统计命令喔!

sort可以依据不同的数据型态对行进行排序! 例如数字与文字的排序就不一样。 此外,排序的字符与语系编码有关,排序前,建议使用LANG=C让语系统一,数据排序比较好一些。

              [peter@study ~]$ sort [-fbMnrtuk] [file or stdin]
            
选项与参数:
-f :忽略大小写的差异,例如 A 与 a 视为编码相同;
-b :忽略最前面的空格符部分;
-M :以月份的名字来排序,例如 JAN, DEC 等等的排序方法;
-n :使用数值型进行排序(默认是以字符型态来排序的);
-r :反向排序;
-u :就是 uniq ,相同的数据中,仅出现一行代表;
-t :分隔符,预设是用 [tab] 键来分隔;
-k :以那个区间 (field) 来进行排序的意思
对/etc/passwd文件中的用户账号进行排序:
              [peter@study ~]$ cat /etc/passwd | sort
              _apt:x:104:65534::/nonexistent:/usr/sbin/nologin
              avahi-autoipd:x:109:114:Avahi autoip daemon,,,:/var/lib/avahi-autoipd:/usr/sbin/nologin
              avahi:x:115:122:Avahi mDNS daemon,,,:/var/run/avahi-daemon:/usr/sbin/nologin
              backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
              bin:x:2:2:bin:/bin:/usr/sbin/nologin
              colord:x:116:123:colord colour management daemon,,,:/var/lib/colord:/usr/sbin/nologin
              cups-pk-helper:x:106:112:user for cups-pk-helper service,,,:/home/cups-pk-helper:/usr/sbin/nologin
              daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
              ...省略...
            
由上面的数据可以看出, sort默认以第一个字段数据来排序,并且默认是以字符型来排序!
将/etc/passwd文件中的内容以第三个字段排序:
              [peter@study ~]$ cat /etc/passwd | sort -t ':' -k 3
              root:x:0:0:root:/root:/bin/bash
              peter:x:1000:1000:peter,,,:/home/peter:/bin/bash
              systemd-network:x:100:102:systemd Network Management,,,:/run/systemd/netif:/usr/sbin/nologin
              mysql:x:1001:1001::/home/mysql:/sbin/nologin
              www:x:1002:1002::/home/www:/sbin/nologin
              uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin
              systemd-resolve:x:101:103:systemd Resolver,,,:/run/systemd/resolve:/usr/sbin/nologin
              ...省略...
            
/etc/passwd文件中的字段是以:作为分隔符,所以需要用-t指定分隔符。由于sort默认是以字符型排序,上面我们可以看到100在1000的后面。 需要使用-n选项,这样sort就会把第三个字段作为数值进行排序:
              [peter@study ~]$ cat /etc/passwd | sort -t ':' -k 3 -n
              root:x:0:0:root:/root:/bin/bash
              daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
              bin:x:2:2:bin:/bin:/usr/sbin/nologin
              sys:x:3:3:sys:/dev:/usr/sbin/nologin
              sync:x:4:65534:sync:/bin:/bin/sync
              games:x:5:60:games:/usr/games:/usr/sbin/nologin
              man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
              lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
              ...省略...
            
sort是很常用的命令。假设有很多的账号,想要知道最大的用户ID目前到哪一号了!使用sort就可以很容易知道答案了!
取last输出中的账号信息并加以排序:
              [peter@study ~]$ last | cut -d ' ' -f1 | sort
            

分区命令: split

回到顶部

split可以将一个大文件,依据文件大小或行数来分区,就可以将大文件分区成为小文件了!
如果你有文件太大,导致一些携带式装置无法复制的问题,就可以先用split将大文件分割成多个小文件。

              [peter@study ~]$ split [-bl] file PREFIX
            
选项与参数:
-b :后面可接欲分区成的文件大小,可加单位,例如 b, k, m 等;
-l :以行数来进行分区。
PREFIX :代表前导符的意思,可作为分区文件的前导文字。
/etc/services文件有六百多K,若想要分成300K一个文件时:
[peter@study ~]$ cd /tmp; split -b 300k /etc/services services [peter@study tmp]$ ll -k services* -rw-rw-r--. 1 peter peter 307200 Jul 9 22:52 servicesaa -rw-rw-r--. 1 peter peter 307200 Jul 9 22:52 servicesab -rw-rw-r--. 1 peter peter 9 22:52 servicesac 55893 Jul
文件名可以随意指定!只要写上前导文字,小文件就会以xxxaa, xxxab, xxxac等方式来建立小文件的!
将上面的三个小文件合成一个文件,文件名为 servicesback:
              [peter@study tmp]$ cat services* >> servicesback
            
就用数据流重导向就好啦!简单!
使用ls -al /输出的信息中,每十行记录成一个文件
              [peter@study tmp]$ ls -al / | split -l 10 - lsroot
              [peter@study tmp]$ wc -l lsroot*
              10 lsrootaa
              10 lsrootab
              4 lsrootac
              24 total
            
重点在那个-!一般来说,如果需要 stdout/stdin 时,但偏偏又没有文件,有的只是 - 时,那么那个 - 就会被当成 stdin 或 stdout ~
在 Windows 操作系统下,你要将文件分区需要如何作?伤脑筋吧!在 Linux 底下就简单的多了!
你要将文件分区的话,那么就使用 -b size 来将一个分区的文件限制其大小,如果是行数的话, 那么就使用-l line 来分区!这样就可以轻易的将你的文件分区成某些软件能够支持的最大容量(例如 gmail 单一信件 25MB 之类的!),方便copy!

字符转换命令: tr, col, join, paste, expand

回到顶部

我们在 vim 程序编辑器当中,提到过 DOS 断行字符与 Unix 断行字符的不同,并且可以使用 dos2unix 与 unix2dos 来完成转换。好了,那么思考一下,是否还有其他常用的字符替代? 举例来 说,要将大写改成小写,或者是将数据中的 [tab] 按键转成空格键?还有,如何将两篇信息整合成一 篇? 底下我们就来介绍一下这些字符转换命令在管道当中的使用方法:

tr可以用来删除一段信息当中的文字,或者是进行文字信息的替换!

              [peter@study ~]$ tr [-ds] SET1 ...
            
选项与参数:
-d :删除信息当中的 SET1 这个字符串;
-s :取代掉重复的字符!
将 last 输出的信息中,所有的小写变成大写字符:
              [peter@study ~]$ last | tr '[a-z]' '[A-Z]'
            
没有加上单引号也是可以执行的,如:last | tr [a-z] [A-Z]
将/etc/passwd输出的信息中,将冒号(:)删除:
              [peter@study ~]$ cat /etc/passwd | tr -d ':'
            
将/etc/passwd转存成dos断行到/root/passwd中,再将^M符号删除:
              [peter@study ~]$ cp /etc/passwd ~/passwd && unix2dos ~/passwd
              [peter@study ~]$ file /etc/passwd ~/passwd
              /etc/passwd: ASCII text /home/peter/passwd: ASCII text, with CRLF line terminators  #就是 DOS 断行
              [peter@study ~]$ cat ~/passwd | tr -d '\r' > ~/passwd.linux    # 那个 \r 指的是 DOS 的断行字符,关于更多的字符,请参考 man tr
              [peter@study ~]$ ll /etc/passwd ~/passwd*
              -rw-r--r--. 1 root
              root
              2092 Jun 17 00:20 /etc/passwd
              -rw-r--r--. 1 peter peter 2133 Jul 9 22:13 /home/peter/passwd
              -rw-rw-r--. 1 peter peter 2092 Jul 9 22:13 /home/peter/passwd.linux
            
# 处理过后,发现文件大小与原本的 /etc/passwd 就一致了!
其实这个命令也可以写在『正规表示法』里头!因为他也是由正规表示法的方式来取代数据的! 以 上面的例子来说,使用 [] 可以设定一串字呢!也常常用来取代文件中的怪异符号! 例如上面第三 个例子当中,可以去除 DOS 文件留下来的 ^M 这个断行的符号!这东西相当的有用!相信处理Linux & Windows 系统中的人们最麻烦的一件事就是这个事情啦! 亦即是 DOS 底下会自动的在每行行尾加入 ^M 这个断行符号!这个时候除了以前讲过的 dos2unix 之外,我们也可以使用这个 tr 来 将 ^M 去除! ^M 可以使用 \r 来代替之!

uniq将输入中重复的行去掉。如果排序完成了,想要将重复的资料仅列出一个显示,就可以用uniq命令

              [peter@study ~]$ uniq [-ic]
            
选项与参数:
-i :忽略大小写字符的不同;
-c :进行计数
uniq命令用来将重复的行删除掉只显示一个 要知道这个月份登入你主机的用户有谁,而不在乎他的登入次数, 那么就可以取出last输出的账号字段,排序后,去掉重复的行:
              [peter@study ~]$ last | cut -d ' ' -f1 | sort | uniq
            
上面的步骤为:
(1)先将所有的数据列出;
(2)再将人名独立出来;
(3)经过排序;
(4)只显示一个! 由于这个命令是在将重复的东西减少,所以当然需要配合排序过的文件』来处理!
上面去掉重复的行后,大部分情况需要统计出现的次数,也就是说,
              [peter@study ~]$ last | cut -d ' ' -f1 | sort | uniq -c
                    1 
                  42 peter
                  36 reboot
                    7 root
                    1 wtmp
            
从上面的结果可以发现reboot有36次登录, root登入则有7次!而peter则登录了42次 !
wtmp 与第一行的空白都是 last 的默认字符,那两个可以忽略的!

参数代换: xargs

回到顶部

xargs 是在做什么的呢?就以字面上的意义来看, x 是加减乘除的乘号,args 则是 arguments (参数) 的意思,所以说,这个玩意儿就是在产生某个命令的参数的意思! xargs 可以读入 stdin 的数据,并 且以空格符或断行字符作为分辨,将 stdin 的资料分隔成为 arguments 。 因为是以空格符作为分隔, 所以,如果有一些文件名或者是其他意义的名词内含有空格符的时候, xargs 可能就会误判了~他的 用法其实也还满简单的!就来看一看先!

              [peter@study ~]$ xargs [-0epn] command
            
选项与参数:
-0 :如果输入的 stdin 含有特殊字符,例如 `, \, 空格键等等字符时,这个 -0 参数 可以将他还原成一般字符。这个参数可以用于特殊状态喔!
-e :这个是 EOF (end of file) 的意思。后面可以接一个字符串,当 xargs 分析到这个字符串时, 就会停止继续工作!
-p :在执行每个命令的 argument 时,都会询问使用者的意思;
-n :后面接次数,每次 command 命令执行时,要使用几个参数的意思。
当 xargs 后面没有接任何的命令时,默认是以 echo 来进行输出喔!
范例一:将 /etc/passwd 内的第一栏取出,仅取三行,使用 id 这个命令将每个账号内容秀出来
              [peter@study ~]$ id root
              uid=0(root) gid=0(root) groups=0(root)
            
# 这个 id 命令可以查询用户的 UID/GID 等信息
              [peter@study ~]$ id $(cut -d ':' -f 1 /etc/passwd | head -n 3)
            
# 虽然使用 $(cmd) 可以预先取得参数,但可惜的是, id 这个命令『仅』能接受一个参数而已!
# 所以上述的这个命令执行会出现错误!根本不会显示用户的 ID 啊!
              [peter@study ~]$ cut -d ':' -f 1 /etc/passwd | head -n 3 | iduid=1000(peter) gid=1000(peter) groups=1000(peter),10(wheel)
            
# 我不是要查自己啊!
# 因为 id 并不是管道命令,因此在上面这个命令执行后,前面的东西通通不见!只会执行 id!
              [peter@study ~]$ cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs id
            
# 依旧会出现错误!这是因为 xargs 一口气将全部的数据通通丢给 id 处理~但 id 就接受 1 个啊最多!
              [peter@study ~]$ cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -n 1 id
              uid=0(root) gid=0(root) groups=0(root)
              uid=1(bin) gid=1(bin) groups=1(bin)
              uid=2(daemon) gid=2(daemon) groups=2(daemon)
            
# 透过 -n 来处理,一次给予一个参数,因此上述的结果就 OK 正常的显示啰!
范例二:同上,但是每次执行 id 时,都要询问使用者是否动作?
              [peter@study ~]$ cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -p -n 1 id
              id root ?...y
              uid=0(root) gid=0(root) groups=0(root)
              id bin ?...y
              .....(底下省略).....
            
# 呵呵!这个 -p 的选项可以让用户的使用过程中,被询问到每个命令是否执行!
范例三:将所有的 /etc/passwd 内的账号都以 id 查阅,但查到 sync 就结束命令串
              [peter@study ~]$ cut -d ':' -f 1 /etc/passwd | xargs -e'sync' -n 1 id
            
# 仔细与上面的案例做比较。也同时注意,那个 -e'sync' 是连在一起的,中间没有空格键。
# 上个例子当中,第六个参数是 sync 啊,那么我们下达 -e'sync' 后,则分析到 sync 这个字符串时,
# 后面的其他 stdin 的内容就会被 xargs 舍弃掉了!
其实,在 man xargs 里面就有三四个小范例,您可以自行参考一下内容。 此外, xargs 真的是很好 用的一个玩意儿!您真的需要好好的参详参详!会使用 xargs 的原因是, 很多命令其实并不支持管 线命令,因此我们可以透过 xargs 来提供该命令引用 standard input 之用!举例来说,我们使用如下 的范例来说明:
范例四:找出 /usr/sbin 底下具有特殊权限的文件名,并使用 ls -l 列出详细属性
              [peter@study ~]$ find /usr/sbin -perm /7000 | xargs ls -l
              -rwx--s--x. 1 root lock
              11208 Jun 10
              2014 /usr/sbin/lockdev
              -rwsr-xr-x. 1 root root 113400 Mar 6 12:17 /usr/sbin/mount.nfs
              -rwxr-sr-x. 1 root root 11208 Mar 6 11:05 /usr/sbin/netreport
              .....(底下省略).....
            
# 聪明的读者应该会想到使用『 ls -l $(find /usr/sbin -perm /7000) 』来处理这个范例!
# 都 OK!能解决问题的方法,就是好方法!

关于减号 - 的用途

回到顶部

管道命令在 bash 的连续的处理程序中是相当重要的!另外,在 log file 的分析当中也是相当重要的 一环, 所以请特别留意!另外,在管道命令当中,常常会使用到前一个命令的 stdout 作为这次的 stdin , 某些命令需要用到文件名 (例如 tar) 来进行处理时,该 stdin 与 stdout 可以利用减号 "-" 来替代, 举例来说:

              [root@initroot ~]# mkdir /tmp/homeback
              [root@initroot ~]# tar -cvf - /home | tar -xvf - -C /tmp/homeback
            
上面这个例子是说:『我将 /home 里面的文件给他打包,但打包的数据不是纪录到文件,而是传送 到 stdout; 经过管道后,将 tar -cvf - /home 传送给后面的 tar -xvf - 』。后面的这个 - 则是取用前 一个命令的 stdout, 因此,我们就不需要使用 filename 了!这是很常见的例子喔!注意注意!

本文由initroot编辑整理,转载请注明www.initroot.com