1
ls -l /tmp > /tmp/test.text

ls -l /tmp 所显示的数据已经被重新导向到 /tmp/test.text文件中了.但是

  1. 该文件 (本例中是 /tmp/test.text) 若不存在,系统会自动的将他建立起来,但是
  2. 当这个文件存在的时候,那么系统就会先将这个文件内容清空,然后再将数据写入!
  3. 也就是若以 > 输出到一个已存在的文件中,那个文件就会被覆盖掉

但是>>则不会覆盖原内容,而是以累加的方式也就是追加的形式。

 1> :以覆盖的方法将『正确的数据』输出到指定的文件或装置上;
 1>>:以累加的方法将『正确的数据』输出到指定的文件或装置上;
 2> :以覆盖的方法将『错误的数据』输出到指定的文件或装置上;
 2>>:以累加的方法将『错误的数据』输出到指定的文件或装置上;

『 1>> 』以及『 2>> 』中间是没有空格的

1
2
承范例二,将 stdout 与 stderr 分存到不同的文件去
$ find /home -name .bashrc > list_right 2> list_error

/dev/null 垃圾桶黑洞装置与特殊写法

1
2
将错误的数据丢弃,屏幕上显示正确的数据
[dmtsai@study ~]$ find /home -name .bashrc 2> /dev/null
1
2
3
4
将指令的数据全部写入名为 list 的文件中
[dmtsai@study ~]$ find /home -name .bashrc > list 2> list <==错误
[dmtsai@study ~]$ find /home -name .bashrc > list 2>&1 <==正确
[dmtsai@study ~]$ find /home -name .bashrc &> list <==正确

standard input : < 与 <<

1
2
3
//用 stdin 取代键盘的输入以建立新文件的简单流程
//将~/.bashrc中的文件内容输入到catfile,并显示在屏幕上
$ cat > catfile < ~/.bashrc

管线命令 (pipe)

每个管线后面接的第一个数据必定是『指令』 ,而且这个指令必须要能够接受 standard input 的数据才行

撷取命令: cut, grep

cut

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
$ cut -d'分隔字符' -f fields <==用于有特定分隔字符
$ cut -c 字符区间 <==用于排列整齐的讯息
选项与参数:
-d :后面接分隔字符。与 -f 一起使用;
-f :依据 -d 的分隔字符将一段讯息分区成为数段,用 -f 取出第几段的意思;
-c :以字符 (characters) 的单位取出固定字符区间;
//将 PATH 变量取出,我要找出第五个路径。
$ echo ${PATH}
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/dmtsai/.local/bin:/home/dmtsai/bin
$ echo ${PATH} | cut -d ':' -f 5
# 如同上面的数字显示,我们是以『 : 』作为分隔,因此会出现 /home/dmtsai/.local/bin
# 那么如果想要列出第 3 与第 5 呢?,就是这样:
$ echo ${PATH} | cut -d ':' -f 3,5
//将 export 输出的讯息,取得第 12 字符以后的所有字符串
$ export | cut -c 12-
HISTCONTROL="ignoredups"
HISTSIZE="1000"
HOME="/home/dmtsai"
HOSTNAME="study.centos.vbird"

grep

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ grep [-acinv] [--color=auto] '搜寻字符串' filename
选项与参数:
-a :将 binary 文件以 text 文件的方式搜寻数据
-c :计算找到 '搜寻字符串' 的次数
-i :忽略大小写的不同,所以大小写视为相同
-n :顺便输出行号
-v :反向选择,亦即显示出没有 '搜寻字符串' 内容的那一行!
--color=auto :可以将找到的关键词部分加上颜色的显示喔!
//将 last 当中,有出现 root 的那一行就取出来;
$ last | grep 'root'
//与范例一相反,只要没有 root 的就取出!
$ last | grep -v 'root'
//在 last 的输出讯息中,只要有 root 就取出,并且仅取第一栏
$ last | grep 'root' |cut -d ' ' -f1
排序命令: sort, wc, uniq

sort

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
$ sort [-fbMnrtuk] [file or stdin]
选项与参数:
-f :忽略大小写的差异,例如 A 与 a 视为编码相同;
-b :忽略最前面的空格符部分;
-M :以月份的名字来排序,例如 JAN, DEC 等等的排序方法;
-n :使用『纯数字』进行排序(默认是以文字型态来排序的);
-r :反向排序;
-u :就是 uniq ,相同的数据中,仅出现一行代表;
-t :分隔符,预设是用 [tab] 键来分隔;
-k :以那个区间 (field) 来进行排序的意思
//个人账号都记录在 /etc/passwd 下,请将账号进行排序。
[dmtsai@study ~]$ cat /etc/passwd | sort
abrt:x:173:173::/etc/abrt:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
alex:x:1001:1002::/home/alex:/bin/bash
# 鸟哥省略很多的输出~由上面的数据看起来, sort 是预设『以第一个』数据来排序,
# 而且默认是以『文字』型态来排序的喔!所以由 a 开始排到最后啰!
// /etc/passwd 内容是以 : 来分隔的,我想以第三栏来排序
$ cat /etc/passwd | sort -t ':' -k 3
root:x:0:0:root:/root:/bin/bash
dmtsai:x:1000:1000:dmtsai:/home/dmtsai:/bin/bash
alex:x:1001:1002::/home/alex:/bin/bash
arod:x:1002:1003::/home/arod:/bin/bash
//利用 last ,将输出的数据仅取账号,并加以排序
$ last | cut -d ' ' -f1 | sort

uniq

1
2
3
4
5
6
7
8
$ uniq [-ic]
选项与参数:
-i :忽略大小写字符的不同;
-c :进行计数
//使用 last 将账号列出,仅取出账号栏,进行排序后仅取出一位;
$ last | cut -d ' ' -f1 | sort | uniq
//承上题,如果我还想要知道每个人的登入总次数呢?
$ last | cut -d ' ' -f1 | sort | uniq -c

wc

1
2
3
4
5
6
7
8
9
$ wc [-lwm]
选项与参数:
-l :仅列出行;
-w :仅列出多少字(英文单字);
-m :多少字符;
那个 /etc/man_db.conf 里面到底有多少相关字、行、字符数?
[dmtsai@study ~]$ cat /etc/man_db.conf | wc
131 723 5171
# 输出的三个数字中,分别代表: 『行、字数、字符数』

tee(双向重定向)

1
2
3
4
5
6
7
8
9
$ tee [-a] file
选项与参数:
-a :以累加 (append) 的方式,将数据加入 file 当中!
$ last | tee last.list | cut -d " " -f1
# 这个范例可以让我们将 last 的输出存一份到 last.list 文件中
$ ls -l /home | tee ~/homefile | more
# 这个范例则是将 ls 的数据存一份到 ~/homefile ,同时屏幕也有输出讯息!
$ ls -l / | tee -a ~/homefile | more
# 要注意! tee 后接的文件会被覆盖,若加上 -a 这个选项则能将讯息累加
字符转换命令: tr, col, join, paste, expand

tr

1
2
3
4
5
6
7
8
9
$ tr [-ds] SET1 ...
选项与参数:
-d :删除讯息当中的 SET1 这个字符串;
-s :取代掉重复的字符!
//将 last 输出的讯息中,所有的小写变成大写字符:
$ last | tr '[a-z]' '[A-Z]'
# 事实上,没有加上单引号也是可以执行的,如:『 last | tr [a-z] [A-Z] 』
//将 /etc/passwd 输出的讯息中,将冒号 (:) 删除
$ cat /etc/passwd | tr -d ':'

col

1
2
3
4
5
6
7
$ col [-xb]
选项与参数:
-x:将 tab 键转换成对等的空格键
//利用 cat -A 显示出所有特殊按键,最后以 col 将 [tab] 转成空白
$ cat -A /etc/man_db.conf <==此时会看到很多 ^I 的符号,那就是 tab
$ cat /etc/man_db.conf | col -x | cat -A | more
# 嘿嘿!如此一来, [tab] 按键会被取代成为空格键,输出就美观多了!

join

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

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ paste [-d] file1 file2
选项与参数:
-d :后面可以接分隔字符。预设是以 [tab] 来分隔的!
- :如果 file 部分写成 - ,表示来自 standard input 的资料的意思。
//用 root 身份,将 /etc/passwd 与 /etc/shadow 同一行贴在一起
# paste /etc/passwd /etc/shadow
root:x:0:0:root:/root:/bin/bash root:$6$wtbCCce/PxMeE5wm$KE2IfSJr...:16559:0:99999:7:::
bin:x:1:1:bin:/bin:/sbin/nologin
bin:*:16372:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin daemon:*:16372:0:99999:7:::
# 注意喔!同一行中间是以 [tab] 按键隔开的!
//先将 /etc/group 读出(用 cat),然后与范例一贴上一起!且仅取出前三行
# cat /etc/group|paste /etc/passwd /etc/shadow -|head -n 3
# 这个例子的重点在那个 - 的使用!那玩意儿常常代表 stdin 喔!

expand

这玩意儿就是在将 [tab] 按键转成空格键

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ expand [-t] file
选项与参数:
-t:后面可以接数字。一般来说,一个 tab 按键可以用 8 个空格键取代。我们也可以自行定义一个 [tab] 按键代表多少个字符呢!
将 /etc/man_db.conf 内行首为 MANPATH 的字样就取出;仅取前三行;
$ 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] 按键设定成 6 个字符的话?
[dmtsai@study ~]$ 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$ split [-bl] file PREFIX
选项与参数:
-b :后面可接欲分区成的文件大小,可加单位,例如 b, k, m 等;
-l :以行数来进行分区。
PREFIX :代表前导符的意思,可作为分区文件的前导文字。
//我的 /etc/services 有六百多 K,若想要分成 300K 一个文件时
$ cd /tmp; split -b 300k /etc/services services
$ ll -k services*
-rw-rw-r--. 1 dmtsai dmtsai 307200 Jul 9 22:52 servicesaa
-rw-rw-r--. 1 dmtsai dmtsai 307200 Jul 9 22:52 servicesab
-rw-rw-r--. 1 dmtsai dmtsai 9 22:52 servicesac
55893 Jul
# 那个档名可以随意取的啦!我们只要写上前导文字,小文件就会以
# xxxaa, xxxab, xxxac 等方式来建立小文件的!
如何将上面的三个小文件合成一个文件,档名为 servicesback
$ cat services* >> servicesback
# 很简单吧?就用数据流重导向就好啦!简单!
参数代换: xargs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
$ xargs [-0epn] command
选项与参数:
-0:如果输入的 stdin 含有特殊字符,例如 `, \, 空格键等等字符时,这个 -0 参数可以将他还原成一般字符。这个参数可以用于特殊状态喔!
-e:这个是 EOF (end of file) 的意思。后面可以接一个字符串,当 xargs 分析到这个字符串时,就会停止继续工作!
-p :在执行每个指令的 argument 时,都会询问使用者的意思;
-n :后面接次数,每次 command 指令执行时,要使用几个参数的意思。
当 xargs 后面没有接任何的指令时,默认是以 echo 来进行输出喔!
#将 /etc/passwd 内的第一栏取出,仅取三行,使用 id 这个指令将每个账号内容秀出来
$ id root
uid=0(root) gid=0(root) groups=0(root) # 这个 id 指令可以查询用户的 UID/GID 等信息
$ id $(cut -d ':' -f 1 /etc/passwd | head -n 3)
# 虽然使用 $(cmd) 可以预先取得参数,但可惜的是, id 这个指令『仅』能接受一个参数而已!
# 所以上述的这个指令执行会出现错误!根本不会显示用户的 ID 啊
$ cut -d ':' -f 1 /etc/passwd | head -n 3 | id
# 因为 id 并不是管线命令,因此在上面这个指令执行后,前面的东西通通不见!只会执行 id!

//正确处理方式
$ 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 时,都要询问使用者是否动作?
$ 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
关于减号 - 的用途

在管线命令当中,常常会使用到前一个指令的 stdout 作为这次的stdin,某些指令需要用到文件名 (例如 tar) 来进行处理时.该 stdin 与 stdout 可以利用减号 “-“来替代.

1
2
3
4
5
# mkdir /tmp/homeback
# tar -cvf - /home | tar -xvf - -C /tmp/homeback
上面这个例子是说:『我将 /home 里面的文件给他打包,但打包的数据不是纪录到文件,而是传送
到 stdout; 经过管线后,将 tar -cvf - /home 传送给后面的 tar -xvf - 』。后面的这个 - 则是取用前
一个指令的 stdout, 因此,我们就不需要使用 filename