cat命令
很多時候我們通過cat
命令來查看文件內容,它會將文件的所有內容顯示出來。當然,cat
也可以通過管道接收數據,它主要完成的是將從管道接收的輸入導到輸出。
more跟less命令
有時候用cat
命令來顯示一個較大的文件并不方便,整個文件內容一次性顯示出來簡直就是刷屏了。如果需要一頁頁的顯示內容,可以使用more
或者less
命令,這兩個命令會以分頁的形式顯示文件內容,至于使用哪個命令完全看個人習慣了。此外,這兩個命令不僅可以分頁顯示,而且在分頁模式下,你可以用快捷鍵方便的瀏覽及搜索:
* 按`d`下翻頁
* 按空格下翻頁
* 按回車下移一行
* 按`/`進入搜索模式,輸入要搜索的關鍵字,按回車搜索。
* 按`n`搜索下一個
* 按`q`退出查看
tee命令
tee
命令一般從管道接收數據,這點與cat
類似,將stdin導到stdout。不同的是,tee
同時還可以指定一個文件作為輸出。這點非常有用,有時候我們想一般看到命令的輸出,同時又希望將輸出保存到文件中,這時候用tee
最為合適。
# date | tee time.log
Mon Nov 20 14:05:02 EST 2017
# cat time.log
Mon Nov 20 14:05:02 EST 2017
date命令
date
命令用來顯示時間跟時區,比較常見的用法有:
-
默認顯示
# date Sun Nov 19 20:08:21 EST 2017 # date -u Mon Nov 20 01:08:28 UTC 2017
其中,
-u
參數表示顯示UTC標準時間,即時區為0的時間。 -
指定顯示格式
除了默認輸出,我們也可以指定顯示的格式:
# date +'%A %d-%m-%Y UTC %:z' Sunday 19-11-2017 UTC -05:00
date
支持非常多元化的格式,具體可以參考這里。 -
顯示當前時間的秒數
通常,在計算當前時間的秒數的時候,我們通常會以Unix Epoch Time為基準,用
date
命令可以非常方便的顯示當前時間的秒數:# date +%s 1511141040 # date +%s --date='2017/11/19 09:56:00' 1511103360
其中,也可以通過參數
--date
指定時間來計算。反過來,如果我們知道了時間的秒數,需要顯示其相對于Unix Epoch Time的時間,可以這么做:# date; date +%s Mon Nov 20 10:33:07 EST 2017 1511191987 # date --date=@1511191987 Mon Nov 20 10:33:07 EST 2017
-
時間偏移計算
有時候需要知道多少天前是什么時間,這時候需要用到時間偏移計算了:
# date --date='100 seconds ago' Sun Nov 19 20:35:44 EST 2017 # date --date='100 hours ago' Wed Nov 15 16:37:28 EST 2017 # date --date='100 days ago' Fri Aug 11 21:37:34 EDT 2017
date
命令可以識別多種時間偏移寫法,除了示例中的,還有minutes months years
等,當然,也可以這樣寫:# date --date='+ 1000 seconds' Sun Nov 19 20:56:28 EST 2017 # date --date='- 1000 seconds' Sun Nov 19 20:23:41 EST 2017 # date --date='2017-11-19 00:00:00 + 1000 seconds' Sat Nov 18 09:00:01 EST 2017
直接用
+
或者-
表示以后或者以前的時間,也可以指定某個時間點然后偏移。 -
設置時間
當然,你也可以通過
date
命令來設置時間:# date Sun Nov 19 20:44:11 EST 2017 # date --set='Sun Nov 19 20:44:30 EST 2017' Sun Nov 19 20:44:30 EST 2017 # date Sun Nov 19 20:44:31 EST 2017
其中
--set
也可以簡寫為-s
,時間格式非常靈活:# date -s '2017/11/20 10:19:50' Mon Nov 20 10:19:50 EST 2017
cal命令
我們用date
可以顯示時間,同時咱們還可以通過cal
命令來顯示日歷:
# cal
November 2017
Su Mo Tu We Th Fr Sa
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 28 29 30
當然,你也可以指定要顯示的日期,比如1949年10月的日歷:
# cal 10 1949
October 1949
Su Mo Tu We Th Fr Sa
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 28 29
30 31
time命令
有時候我們需要知道一個命令運行了多少時間,這時候我們可以用time
命令來計時:
# time sleep 1
real 0m1.018s
user 0m0.001s
sys 0m0.002s
其中sleep 1
用來睡眠1秒,real
表示實際用了多少時間,user
表示在用戶態花了多少時間,sys
則表示在內核花了多少時間。詳細可以參考這篇問答。
wc命令
wc
命令是Word Count
的簡稱,顧名思義就是用來統計單詞的。
# cat test.log
Nov 17 00:27:20 traffic-base1 named[1212]: managed-keys-zone: Unable to fetch DNSKEY set .: timed out
# cat test.log | wc -w
14
參數-w
表示統計單詞數,這里的單詞實際上指的是被空格分開的字符串。下面列舉出wc
命令的有關參數:
參數 | 說明 |
---|---|
-w | 統計多少單詞 |
-l | 統計多少行 |
-c | 統計有多少個字節 |
-m | 統計有多少個字符 |
-L | 統計長度最長的行的長度 |
注意,這里的字節跟字符的差別,在英文中基本上是一樣的,但是在多字節語言中,其意義就不一樣了:
# echo '你好' | wc -c
7
# echo '你好' | wc -m
3
find命令
find
命令用來查找文件或目錄,這又是一個非常強大的且常用的命令,這里只介紹幾種常見的用法:
-
根據文件名查找
這是基本且常見的用法:
# find . -name "test*" ./test.log ./test2
示例中表示在當前目錄(用
.
表示)下包括其子目錄,查找文件名以test
開頭的文件。默認情況下,find
命令是大小寫敏感的,如果需要忽略大小寫,則可以改用參數-iname
。 -
根據類型查找
可以根據類型查找文件:
# find . -type f ./Test1 ./test.log ./test2
當然,也可以同時根據類型跟文件名一起查找:
# find . -type f -name "test*" ./test.log ./test2
f
表示文件,如果是查找目錄的話則用d
。 -
根據時間查找
find
命令還可以根據時間來查找文件目錄,其中一個用法如下:find . -newer base_file
表示在當前目錄下查找比
base_file
文件更新的文件或者目錄。此外,find
還可以根據文件的atime, ctime, mtime來查找文件,如下,根據修改時間來查找:# date Fri Nov 17 20:34:52 EST 2017 # ll total 20 drwxr-xr-x. 2 root root 45 Nov 17 02:46 ./ dr-xr-x---. 48 root root 8192 Nov 17 02:46 ../ -rw-r--r--. 1 root root 0 Nov 16 00:17 Test1 -rw-r--r--. 1 root root 34 Nov 17 02:46 test2 -rw-r--r--. 1 root root 102 Nov 17 00:30 test.log # find . -mtime -1 . ./test.log ./test2
其中
-mtime
表示根據修改時間查找,-1
表示最近一天。find
支持的時間查找總結如下:
參數 | 說明 |
---|---|
-mtime | 根據修改時間,也就是ls -l 顯示的時間 |
-atime | 根據訪問時間,也就是ls -lu 顯示的時間 |
-ctime | 根據狀態改變的時間,也就是ls -lc 顯示的時間 |
時間值的表示說明:基準+0
表示一天前,-1.5
表示最近1.5天,+1.5
表示2.5天前
-
邏輯查找
find
支持與或非邏輯的查找,比如查找所有C++的源文件,實際上需要找出后綴為.cpp
跟.h
的文件,需要用到find
的邏輯或的查找:find . -name "*.cpp" -o -name "*.h"
其中
-o
是-or
的縮寫,用來表示邏輯或的關系,而-name "*.cpp"
與-name "*.h"
為表達式,構成了EXP1 or EXP2
的關系,只要文件或者目錄滿足其中一個表達式就會輸出。find
支持的邏輯關系如下:
邏輯 | 參數 | 說明 |
---|---|---|
與 | -a |
-and 的縮寫,邏輯與的關系,如find . -type f -a -name "*.log"
|
或 | -o |
-or 的縮寫,邏輯或的關系, 如find . -name "*.cpp" -o -name "*.h"
|
非 | ! |
-not 的縮寫,邏輯非的關系, 如find . ! -name "*.cpp"
|
此外,find
命令還有一個非常重要且常見的用法,就是在找到文件后執行某個命令,改用法如下:
find . -name "*.log" -exec rm {} \;
表示刪除當前目錄包括子目錄中以.log
為后綴的所有文件。其中,-exec
表示在找到后需要執行命令,而命令為rm {} \;
,實際上此命令就是一般的shell
命令,其中{}
用來指代找到的文件或目錄,這里;
必須轉義,因為需要傳遞給find
本身,如果不轉義,則會直接被shell
解析使用了。每找到一個文件或目錄,都會執行指定的命令,其中{}
部分以文件路徑替代。如果需要只執行一次命令,而把所有找到的文件作為參數傳遞給該命令,則需要用+
替代\;
,如:
find . -name "*.log" -exec rm {} +
假定找到的文件有test.log
,test1.log
,用\;
的方式相當于執行兩次:rm test.log
跟rm test1.log
;如果使用+
則只有一次命令rm test.log test1.log
。
sort命令
顧名思義,這個命令就是用來排序的。
# head -n 5 /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
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
root:x:0:0:root:/root:/bin/bash
默認情況下,sort
命令以字典順序對每行進行排序,如果不帶參數,會將整行作為一個字符串進行比較。當然,你也可以指定以第幾列進行排序:
# head -n 5 /etc/passwd | tr : " " | sort -k 3
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
lp x 4 7 lp /var/spool/lpd /sbin/nologin
這里先將:
換成空格(關于tr
命令,請參照本文關于tr
命令的章節),然后以-k
為參數,指定以第三列進行排序。下面列舉其常用的一些參數:
參數 | 說明 |
---|---|
-k | 以第幾列排序,列以空格為分隔 |
-r | 默認sort 以升序輸出,-r 參數則可以以降序輸出 |
-n | 在指定第幾列的時候,可以強制sort 把列的值以數字值進行排序,如下面的例子 |
-t | 默認情況下認為列是以空格為分隔,-t 參數則可以指定分隔符,這樣,上面的例子其實可以直接寫成sort -t : -k 3
|
-f | 忽略大小寫 |
-u | 如果排序后出現重復的行,加上這個參數將只顯示一行 |
# cat test2
10
3
5
3
# cat test2 | sort
10
3
3
5
# cat test2 | sort -n
3
3
5
10
# cat test2 | sort -n -u
3
5
10
uniq命令
uniq
是unique
的簡寫,用來消除sort
排序后重復的行,即相當于sort
命令中的-u
參數。但是,uniq
不僅可以消除重復行,它還可以顯示分別重復了多少行:
# cat test2 | sort -n | uniq -c
2 3
1 5
1 10
還有些常用的參數如下:
參數 | 說明 |
---|---|
-i | 忽略大小寫 |
-d | 只打印有重復的行,每組一個,如果要打印組內所有的,則用-D
|
-u | 只打印沒有重復的行 |
-f | 比較的時候,忽略前面的N列 |
-s | 比較的時候,忽略前面的N個字符 |
od命令
od
可以用來顯示二進制文件:
# cat test2
abcdefg
1234567
# od -t x1 test2
0000000 61 62 63 64 65 66 67 0a 31 32 33 34 35 36 37 0a
0000020
當然,也可以直接顯示字符:
# od -c test2
0000000 a b c d e f g \n 1 2 3 4 5 6 7 \n
0000020
當然,如果僅僅只是顯示二進制內容,還可以使用hexdump
命令了。
壓縮類命令
tar命令
在Linux中,用的最多的壓縮命令就是tar
命令了,在介紹其用法之前,需要清楚幾個概念:
-
存檔文件(Archive File)
存檔文件用來打包多個文件成一個文件,以方便在網絡上傳輸。請注意,打包成的文件并沒有被壓縮。在Linux或Unix系統中,TAR文件是最為常用的存檔文件(通常以
.tar
為文件后綴)。TAR文件的更多解釋可以參考這里。用tar
命令可以生產TAR文件,示例如下:tar cvf tmp.tar tmp/
具體參數在下面會具體解釋,不帶任何壓縮格式的話,
tar
命令會生成一個TAR文件。相應的,如果需要解開TAR文件,可以這么做:tar xvf tmp.tar
-
壓縮文件(Compressed File)
TAR文件是沒有被壓縮的,大小基本保持不變。如果需要對文件進行壓縮,則需要在
tar
命令中加入壓縮格式對應的參數,具體在下面會說明。
下面來詳細介紹tar
命令的用法,tar
的用法如下:
# tar --help
Usage: tar [OPTION...] [FILE]...
tar
命令支持非常多的參數,這里列舉比較常用的幾種使用方式:
-
壓縮文件或目錄
# tar czvf tmp.tgz tmp/ tmp/ tmp/Test1 tmp/test.log tmp/test2
其中,
czvf
表示參數選項;tmp.tgz
表示壓縮后的文件名,通常tgz
是tar.gz
的簡寫;tmp/
表示被壓縮的目錄。參數的解釋如下:參數 說明 c Create
的簡寫,表示生產壓縮文件z 表示采用 gzip
的壓縮格式,文件后綴通常為.tar.gz
或者.tgz
v 表示顯示壓縮的過程,會列出所有被壓縮的文件 f 指定壓縮文件
需要注意的是,tar
支持不同的壓縮格式,除了gzip
之外,還有:
參數 | 說明 |
---|---|
j | 采用bzip2 的壓縮格式,文件后綴通常為.bz2
|
--lzip |
采用lzip 的壓縮格式,文件后綴通常為.lz
|
--xz |
采用xz 的壓縮格式,文件后綴通常為.xz
|
--lzma |
采用lzma 的壓縮格式,文件后綴通常為.lzma
|
更多格式可以參考這里。當然,最為常用的兩種格式為gzip
跟bzip2
,用法示例如下:
tar czvf tmp.tgz tmp/
tar cjvf tmp.bz2 tmp/
其中v
參數可選,如果不需要顯示壓縮過程的話。需要注意的是,tar
壓縮目錄的時候會保持目錄的結構。
-
解壓文件
對應于不同的壓縮格式,解壓參數稍微不一樣,對于
gzip
跟bzip2
分別示例如下:tar xzvf tmp.tgz tar xjvf tmp.tgz
與壓縮不同,
c
換成x
表示解壓,其它參數含義與壓縮一樣。默認情況下,解壓的文件會放在當前目錄,如果需要解壓到某個目錄下,則可以用-C
參數:tar xzvf -C /tmp/ tmp.tgz tar xjvf -C /tmp/ tmp.tgz
-
列出壓縮包里面的文件
有時候我們需要先看看壓縮包里面有哪些文件,但又并不想解壓文件,可以采用
-t
參數:# tar czf tmp.tgz tmp/ # tar tvf tmp.tgz drwxr-xr-x root/root 0 2017-11-17 02:46 tmp/ -rw-r--r-- root/root 0 2017-11-16 00:17 tmp/Test1 -rw-r--r-- root/root 102 2017-11-17 00:30 tmp/test.log -rw-r--r-- root/root 34 2017-11-17 02:46 tmp/test2
其中,
tvf
會列出壓縮包中的文件,不論采用何種壓縮格式,甚至是沒有被壓縮的TAR文件。 -
從壓縮包中提取特定的文件
在列出壓縮包里面的內容后,如果只想提取里面的某些文件,可以這么做:
# tar xzvf tmp.tgz tmp/test.log tmp/test2 tmp/test.log tmp/test2
其中,根據不同的壓縮格式請替換成不同的參數。請務必注意,指定的文件必須是完整的路徑,而不能只是文件名。
另外,如果想提取一組匹配某種條件的文件,可以使用
--wildcards
參數:# tar xzvf tmp.tgz --wildcards "*.log" tmp/test.log
split命令
split
命令用來將一個文件分成多個文件,比如將一個特別大的文件分成平均大小為100M的多個文件等。
# split -b 40M go1.6.linux-amd64.tar.gz go1.6.linux-amd64.tar.gz.part
# ll go1.6.linux-amd64.tar.gz.part*
-rw-r--r--. 1 root root 41943040 Nov 20 15:03 go1.6.linux-amd64.tar.gz.partaa
-rw-r--r--. 1 root root 41943040 Nov 20 15:03 go1.6.linux-amd64.tar.gz.partab
-rw-r--r--. 1 root root 913400 Nov 20 15:03 go1.6.linux-amd64.tar.gz.partac
其中,go1.6.linux-amd64.tar.gz
是要被拆分的文件,go1.6.linux-amd64.tar.gz.part
是拆分后文件的前綴,可以看到文件被拆分為三部分了。
split
非常常見的用法是來將某個被壓縮的文件拆分成小的部分,正如上例所示。那么,如何將拆分的文件重新合并呢?我們可以用cat
將它們合并:
cat go1.6.linux-amd64.tar.gz.part* > go1.6.linux-amd64.tar.gz
grep命令
過濾數據來說,用的最多的估計就是grep
命令了,grep
命令可以從文件或者管道中搜索數據并打印出來,當然,其也可以直接在目錄中搜索所有的文件,并把其中符合條件的行打印出來。
# cat test.log | grep hello
hello
# grep hello test.log
hello
# grep hello . -r
./test.log:hello
上面就是三種方式搜索包括hello
關鍵字的行。
grep
是Linux中使用最為頻繁的命令之一,其本身也有非常強大的功能,這一節咱們將詳細講述其比較常見的用法。
基本查找
查看grep
的幫助可以看到:
# grep --help
Usage: grep [OPTION]... PATTERN [FILE]...
其中OPTION
指的是命令參數,PATTERN
指的是匹配的字符串,比如關鍵字搜索。FILE
指的是文件,當然,沒有文件的時候也可以通過管道接收數據并搜索過濾。grep
提供了非常多的命令參數用來控制查找的方式跟效果,下面列舉其常用的一些參數:
參數 | 說明 |
---|---|
-i | 默認情況下,grep 命令的搜索是大小寫敏感的,如果需要忽略大小寫可以用這個參數 |
-v | 該參數表示不包含的意思 |
-A2 | 其中A 是after 的意思,表示同時顯示搜索出來行后面兩行。有時候我們需要知道匹配行后面是什么,可以用這個參數 |
-B2 | 與A 相反,其是before 的意思,表示同時顯示匹配行前兩行 |
-C2 | 有時候我們想既顯示前面兩行也顯示后面兩行,這時候就用這個參數 |
-r | 搜索目錄的時候需要帶上這個參數 |
-n | 有些時候,我們需要知道匹配到的行是第幾行,可以加上這個參數把行號打印出來 |
對于PATTERN
,grep
命令也支持不同的用法:
- 關鍵字匹配
這個是最常用的基本用法,匹配是否包括該關鍵字的行。
- 正則匹配
除了基本的關鍵字匹配,grep
還支持極為強大的正則表達式的匹配。我們將在下一小節專門講述正則表達式匹配。
- 或匹配
有時候我們需要匹配某個PATTERN1或者PATTERN2的行,這時候可以這么寫PATTERN
:PATTERN1\|PATTERN2
。通過\|
將多個PATTERN
連在一起表示或的意思,只要匹配其中任一個的行都會被打印出來。
# grep '12306\|test' . -r
./test2:http://abcdefg.test.com
./test2:12306.com
正則表達式匹配
grep
命令支持非常強大的正則匹配,支持三種不同的正則表達式:
- ERE(POSIX-Extended Regular Expressions)
- BRE(POSIX_Basic_Regular_Expressions)
- Perl Regular expression
當然,比較常用的是ERE
正則表達式了。在grep
命令中,采用-E
參數即可以使用該表達式,正則表達式非常靈活,用法非常多,這里列舉幾個示例:
-
匹配以關鍵字開頭的行
grep -E "^keyword" . -r
-
匹配以關鍵字結尾的行
grep -E "keyword$" . -r
-
匹配包含如
2017/10/11
日期的行grep -E "[0-9]{4}/[0-9]{2}/[0-9]{2}" . -r
注意的是,對于數字的表示,其不支持如
\d
這樣的表達方式,而需要[0-9]
這樣表達。
當然,如果需要熟練掌握grep
的正則表達式匹配,你必須對正則表達式非常熟悉,這個就不在本篇的范疇了。
awk命令
要說Linux中最為強大的基本命令有哪些,那awk
無疑會榜上有名,其強大的流式處理能力,很多人甚至寫書來專門講這個命令。這里咱們暫時介紹基本的功能,以后有機會將專門開辟一文來展開。
一個常見的用法就是把文件中的某幾列打印出來:
# cat test.log
Nov 17 00:27:20 traffic-base1 named[1212]: managed-keys-zone: Unable to fetch DNSKEY set .: timed out
# cat test.log | awk '{print $1, $2, $3}'
Nov 17 00:27:20
如上例,空格將一行分成了不同的列,咱們希望只把時間顯示出來,而時間包括了第1,2,3列,因此,通過awk '{print $1, $2, $3}'
就實現了此功能,其中$1
就是引用第一列。
cut命令
有時候,一行內的數據并不是通過空格分隔開的,而是通過其它分隔符,那如何顯示想要的列呢?通過cut
命令,咱們同樣可以輕松實現:
# head -n 5 /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
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
# head -n 5 /etc/passwd | cut -d: -f1
root
bin
daemon
adm
lp
/etc/passwd
中的每一行基本上都是通過:
進行分隔,其中第一列表示用戶名,如果咱們只想把用戶名輸出的話,可以通過cut -d: -f1
來實現,其中-d:
表示以:
號為分隔符,-f1
表示顯示第一列。可見,對于cut
命令來說,咱們可以指定分隔符,那么前面通過awk
實現的例子也可以通過cut
來做:
# cat test.log
Nov 17 00:27:20 traffic-base1 named[1212]: managed-keys-zone: Unable to fetch DNSKEY set .: timed out
# cat test.log | cut -d" " -f1-3
Nov 17 00:27:20
其中-d" "
表示以空格為分隔符(注意,這里的空格必須以引號括起來,不然會被shell展開去除多余空格),-f1-3
表示輸出第1到3列,這里簡用了-
來表示范圍,當然也可以寫成-f1,2,3
了。
此外,cut
命令還可以指定輸出哪些位的字符:
# cat test.log
Nov 17 00:27:20 traffic-base1 named[1212]: managed-keys-zone: Unable to fetch DNSKEY set .: timed out
# cat test.log | cut -c1-16
Nov 17 00:27:20
其中,-c1-16
表示輸出第1到16個字符,當然,你同樣可以以,
來分別列舉要輸出哪幾個。
tr命令
tr
其實是translate
的縮寫,這個命令用來將某些字符翻譯成另外的字符。
# tr --help
Usage: tr [OPTION]... SET1 [SET2]
這個命令就是把字符集SET1
中的字符對應的轉成字符集SET2
中的字符。如將小寫轉成大寫:
# cat test.log
Nov 17 00:27:20 traffic-base1 named[1212]: managed-keys-zone: Unable to fetch DNSKEY set .: timed out
# cat test.log | tr a-z A-Z
NOV 17 00:27:20 TRAFFIC-BASE1 NAMED[1212]: MANAGED-KEYS-ZONE: UNABLE TO FETCH DNSKEY SET .: TIMED OUT
這里用-
來方便的表示一定范圍的字符集,當然,你完全可以一個個列出來你要的字符集。通常情況下,SET1
跟SET2
的長度保持一致,因為這個轉換實際上是一對一的轉換,當然,SET2
的長度是可以大于SET1
的,多余的字符不會被使用。但是,當SET2
長度小于SET1
時,tr
命令會將SET2
中最后一個字符填充不足的位數:
# echo 'abcdefg' | tr ab wyz
wycdefg
# echo 'abcdefg' | tr abcdefg wyz
wyzzzzz
對于tr
還有一個常見的用途,就是用來去除字符串中的換行符:
# head -n 5 /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
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
# head -n 5 /etc/passwd | tr '\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 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
其中,\n
表示換行符,示例中將換行符全部換成了空格。
最后,tr
還有一個常見的用法,可以加上-d
參數來刪除字符集中的字符。
# echo abcdeWXYZ | tr -d a-z
WXYZ
示例中刪除了所有小寫字母。
sed命令
流式處理中,sed
也是一個極為常用的命令,它可以用來替換字串,比之前的tr
那是要強大無數倍了。
查看sed
的幫助:
# sed --help
Usage: sed [OPTION]... {script-only-if-no-other-script} [input-file]...
它既可以直接在文件中替換字符串,也可以加收管道的數據。如基本用法:
# echo abcdefgabcd | sed 's/abc/ABC/'
ABCdefgabcd
其中's/abc/ABC/'
指定了替換的規則,默認情況下只替換一次,如果需要全部替換,則需要在規則后面加入g
:
# echo abcdefgabcd | sed 's/abc/ABC/g'
ABCdefgABCd
規則中默認使用了/
為分隔。當然,你也可以使用其他分隔符,這在要替換的字串中帶有/
的時候特別有用:
# echo "http://abc.test.com" | sed 's/http:\/\//https:\/\//'
https://abc.test.com
# echo "http://abc.test.com" | sed 's|http://|https://|'
https://abc.test.com
如果不指定新的分隔符|
,那么就得使用轉義符\
將//
進行轉義了,這樣可讀性就差了很多,采用|
就自然多了。sed
支持的分隔符還包括了:
,_
。
此外,sed
不僅可以用來替換字串,還可以用來刪除匹配的行:
# cat test2
http://abcdefg.test.com
12306.com
# cat test2 | sed '/12306/d'
http://abcdefg.test.com
高級用法
-
后向引用(Back Referencing)
sed
規則匹配到的字符串還可以在規則定義中被引用,如下例:# echo "hello world" | sed 's/hello/&&/' hellohello world
其中,
&
可以用來引用被匹配到的字串,在本例中,匹配到的字串是hello
,這樣通過&
就可以引用被匹配到的字串了。此外,我們還可以通過()
來指定匹配的字串,并用\1
(數字表示第一個()
)來引用(實際上是正則表達式中的Grouping):# echo Sunday | sed 's/\(Sun\)/\1ny/' Sunnyday # echo Sunday | sed 's/\(Sun\)/\1ny \1/' Sunny Sunday
-
正則匹配
由上述可以看出,
sed
的規則使用了正則表達式規則,但是其書寫跟一般的正則書寫不一樣,你必須將有關的字符轉義,否則sed
仍然會將其當做普通字符進行匹配:# echo "this is aaaa cat" | sed 's/a{4}/a/' this is aaaa cat # echo "this is aaaa cat" | sed 's/a\{4\}/a/' this is a cat
可以看出,在沒有轉義
{
及}
之前,sed
并沒有匹配到目標字串aaaa
,而將其轉義之后,則以正則表達式a{4}
匹配到了aaaa
并進行了替換。 -
遞歸替換
有時候我們需要在項目目錄下替換某個字串,比如把手誤寫錯的
#include<stdllib.h>
全部替換成#include<stdlib.h>
,希望被替換的文件包括*.cpp
,*.h
的文件。其中的一種做法如下:$ head -n 1 test.cpp #include <stdllib.h> $ sed -i 's/#include <stdllib.h>/#include <stdlib.h>/' `find . -name "*.cpp" -o -name "*.h"` $ head -n 1 test.cpp #include <stdlib.h>
這里用到了shell嵌入的用法(可以參看這一篇博文),通過
find
命令找出所有的源文件,然后用sed -i
進行替換,其中-i
表示從文件里面替換。這一用法會將find
找到的所有文件作為參數都追加到sed
命令后,在項目非常大的情況下可能會導致命令執行失敗(因為數量龐大的文件導致追加的參數太大了),通常我們推薦采用find
的這種用法:find . -name "*.cpp" -o -name "*.h" -exec sed -i 's/#include <stdllib.h>/#include <stdlib.h>/' {} \;
具體可以參照本文中關于
find
命令的介紹。
本博文還可以在博主個人主頁中找到。