Linux必懂知识大总结(下)
AWK/SED
awk
awk是一個強大的文本分析工具,相對于grep的查找,sed的編輯,awk在其對數(shù)據(jù)分析并生成報告時,顯得尤為強大。簡單來說awk就是把文件逐行的讀入,以空格為默認分隔符將每行切片,切開的部分再進行各種分析處理。
awk '{pattern + action}' {filenames}
?
統(tǒng)計ip
cat test.txt | awk '{print $2}' | sort | uniq -c | sort -n -r | head -n 1
sed 編輯文本
sed -e 's/foo/bar/' myfile
將 myfile 文件中每行第一次出現(xiàn)的foo用字符串bar替換,然后將該文件內容輸出到標準輸出
sed -e 's/foo/bar/g' myfile
g 使得 sed 對文件中所有符合的字符串都被替換
sed -i 's/foo/bar/g' myfile
選項 i 使得 sed 修改文件
sed -i 's/foo/bar/g' ./m*
批量操作當前目錄下以 m 開頭的文件
sed -i 's/foo/bar/g' `grep foo -rl --include="m*" ./`
``括起來的grep命令,表示將grep命令的的結果作為操作文件
grep 命令中,選項r表示查找所有子目錄,l表示僅列出符合條件的文件名,用來傳給sed命令做操作,--include="m*" 表示僅查找 m 開頭的文件
管道
管道是linux提供的一種常見的進程通信工具
管道中的數(shù)據(jù)只能讀取一次
管道的實現(xiàn)并沒有使用專門的數(shù)據(jù)結構,而是借助了文件系統(tǒng)的file結構和VFS的索引節(jié)點inode。通過將兩個 file 結構指向同一個臨時的 VFS 索引節(jié)點,而這個 VFS 索引節(jié)點又指向一個物理頁面而實現(xiàn)的。
IO模型
mmap
零拷貝技術:讓數(shù)據(jù)傳輸不需要經(jīng)過user space 使用mmap
mmap系統(tǒng)調用導致文件的內容通過DMA模塊被復制到內核緩沖區(qū)中,該緩沖區(qū)之后與用戶進程共享,這樣就內核緩沖區(qū)與用戶緩沖區(qū)之間的復制就不會發(fā)生。
sendfile
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
?
參數(shù)特別注意的是:in_fd必須是一個支持mmap函數(shù)的文件描述符,也就是說必須指向真實文件,不能使用socket描述符和管道。
out_fd必須是一個socket描述符。
由此可見sendfile幾乎是專門為在網(wǎng)絡上傳輸文件而設計的。
?
Sendfile 函數(shù)在兩個文件描述符之間直接傳遞數(shù)據(jù)(完全在內核中操作,傳送),從而避免了內核緩沖區(qū)數(shù)據(jù)和用戶緩沖區(qū)數(shù)據(jù)之間的拷貝,操作效率很高,被稱之為零拷貝。
?
select poll(NIO)
select poll epoll都是IO多路復用的實現(xiàn)方式!
select系統(tǒng)調用的目的是:在一段指定時間內,監(jiān)聽用戶感興趣的文件描述符上的可讀、可寫和異常(異常不包括網(wǎng)絡斷開)事件。poll和select應該被歸類為這樣的系統(tǒng)調用,它們可以阻塞地同時探測一組支持非阻塞的IO設備,直至某一個設備觸發(fā)了事件或者超過了指定的等待時間——也就是說它們的職責不是做IO,而是幫助調用者尋找當前就緒的設備。
int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout);
?
fd_set結構體是文件描述符集,該結構體實際上是一個整型數(shù)組,數(shù)組中的每個元素的每一位標記一個文件描述符。fd_set能容納的文件描述符數(shù)量由FD_SETSIZE指定,一般情況下,FD_SETSIZE等于1024,這就限制了select能同時處理的文件描述符的總量。
?
1)nfds參數(shù)指定被監(jiān)聽的文件描述符的總數(shù)。通常被設置為select監(jiān)聽的所有文件描述符中最大值加1;
2)readfds、writefds、exceptfds分別指向可讀、可寫和異常等事件對應的文件描述符集合。這三個參數(shù)都是傳入傳出型參數(shù),指的是在調用select之前,用戶把關心的可讀、可寫、或異常的文件描述符通過FD_SET函數(shù)分別添加進readfds、writefds、exceptfds文件描述符集,select將對這些文件描述符集中的文件描述符進行監(jiān)聽,如果有就緒文件描述符,select會重置readfds、writefds、exceptfds文件描述符集來通知應用程序哪些文件描述符就緒。這個特性將導致select函數(shù)返回后,再次調用select之前,必須重置我們關心的文件描述符,也就是三個文件描述符集已經(jīng)不是我們之前傳入 的了。
3)timeout參數(shù)用來指定select函數(shù)的超時時間。
?
1)如果指定timeout為NULL,select會永遠等待下去,直到有一個文件描述符就緒,select返回;
2)如果timeout的指定時間為0,select根本不等待,立即返回;
3)如果指定一段固定時間,則在這一段時間內,如果有指定的文件描述符就緒,select函數(shù)返回,如果超過指定時間,select同樣返回。
?
select的幾大缺點:
1)每次調用select,都需要把fd集合從用戶態(tài)拷貝到內核態(tài),這個開銷在fd很多時會很大
2)每次調用select都需要在內核遍歷傳遞進來的所有fd,這個開銷在fd很多時也很大(不適合服務器,但客戶端也可以使用)
3)select支持的文件描述符數(shù)量太小了,默認是1024
?
?
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
與select非常類似,poll比select的好處就是沒有描述符數(shù)量限制,select 有1024 的限制,描述符不能超過此值,poll不受限制。
此函數(shù)在系統(tǒng)調用select內部被使用,作用是把當前的文件指針掛到設備內部定義的等待
隊列中。
?
send不是立即發(fā)送數(shù)據(jù),而是將數(shù)據(jù)放在本地網(wǎng)卡緩沖區(qū)中。
epoll(NIO)
select,poll還是在應用中輪詢Socket,容易浪費;OS會自動輪詢,通過epoll_wait返回。
epoll 與select和poll在使用和實現(xiàn)上有很大區(qū)別。首先,epoll使用一組函數(shù)來完成,而不是單獨的一個函數(shù);其次,epoll把用戶關心的文件描述符上的事件放在內核里的一個事件表中,無須向select和poll那樣每次調用都要重復傳入文件描述符集合事件集。
?
系統(tǒng)調用:
epoll_create 創(chuàng)建一個epoll對象,一般epollfd = epoll_create()
?
epoll_ctl (epoll_add/epoll_del的合體),往epoll對象中增加/刪除某一個流的某一個事件
比如
epoll_ctl(epollfd, EPOLL_CTL_ADD, socket, EPOLLIN);//注冊緩沖區(qū)非空事件,即有數(shù)據(jù)流入
epoll_ctl(epollfd, EPOLL_CTL_DEL, socket, EPOLLOUT);//注冊緩沖區(qū)非滿事件,即流可以被寫入
epoll_wait(epollfd,...)等待直到注冊的事件發(fā)生
(注:當對一個非阻塞流的讀寫發(fā)生緩沖區(qū)滿或緩沖區(qū)空,write/read會返回-1,并設置errno=EAGAIN。而epoll只關心緩沖區(qū)非滿和緩沖區(qū)非空事件)。
?
對于第一個缺點,epoll的解決方案在epoll_ctl函數(shù)中。每次注冊新的事件到epoll句柄中時(在epoll_ctl中指定EPOLL_CTL_ADD),會把所有的fd拷貝進內核,而不是在epoll_wait的時候重復拷貝。epoll保證了每個fd在整個過程中只會拷貝一次。
?
對于第二個缺點,epoll的解決方案不像select或poll一樣每次都把current輪流加入fd對應的設備等待隊列中,而只在epoll_ctl時把current掛一遍(這一遍必不可少)并為每個fd指定一個回調函數(shù),當設備就緒,喚醒等待隊列上的等待者時,就會調用這個回調函數(shù),而這個回調函數(shù)會把就緒的fd加入一個就緒鏈表。epoll_wait的工作實際上就是在這個就緒鏈表中查看有沒有就緒的fd(利用schedule_timeout()實現(xiàn)睡一會,判斷一會的效果,和select實現(xiàn)中的第7步是類似的)。
?
對于第三個缺點,epoll沒有這個限制,它所支持的FD上限是最大可以打開文件的數(shù)目,這個數(shù)字一般遠大于2048,舉個例子,在1GB內存的機器上大約是10萬左右,具體數(shù)目可以cat /proc/sys/fs/file-max察看,一般來說這個數(shù)目和系統(tǒng)內存關系很大。
?
總結:
1)select,poll實現(xiàn)需要自己不斷輪詢所有fd集合,直到設備就緒,期間可能要睡眠和喚醒多次交替。而epoll其實也需要調用epoll_wait不斷輪詢就緒鏈表,期間也可能多次睡眠和喚醒交替,但是它是設備就緒時,調用回調函數(shù),把就緒fd放入就緒鏈表中,并喚醒在epoll_wait中進入睡眠的進程。雖然都要睡眠和交替,但是select和poll在“醒著”的時候要遍歷整個fd集合,而epoll在“醒著”的時候只要判斷一下就緒鏈表是否為空就行了,這節(jié)省了大量的CPU時間。這就是回調機制帶來的性能提升。
2)select,poll每次調用都要把fd集合從用戶態(tài)往內核態(tài)拷貝一次,并且要把current往設備等待隊列中掛一次,而epoll只要一次拷貝,而且把current往等待隊列上掛也只掛一次(在epoll_wait的開始,注意這里的等待隊列并不是設備等待隊列,只是一個epoll內部定義的等待隊列)。這也能節(jié)省不少的開銷。
?
epoll原理
邊緣觸發(fā)模式ET(Edge_triggered)和水平觸發(fā)模式LT(Level_triggered)
Level_triggered(水平觸發(fā)):當被監(jiān)控的文件描述符上有可讀寫事件發(fā)生時,epoll_wait()會通知處理程序去讀寫。如果這次沒有把數(shù)據(jù)一次性全部讀寫完(如讀寫緩沖區(qū)太小),那么下次調用 epoll_wait()時,它還會通知你在上沒讀寫完的文件描述符上繼續(xù)讀寫,當然如果你一直不去讀寫,它會一直通知你!!!如果系統(tǒng)中有大量你不需要讀寫的就緒文件描述符,而它們每次都會返回,這樣會大大降低處理程序檢索自己關心的就緒文件描述符的效率!!!
?
Edge_triggered(邊緣觸發(fā)):當被監(jiān)控的文件描述符上有可讀寫事件發(fā)生時,epoll_wait()會通知處理程序去讀寫。如果這次沒有把數(shù)據(jù)全部讀寫完(如讀寫緩沖區(qū)太小),那么下次調用epoll_wait()時,它不會通知你,也就是它只會通知你一次,直到該文件描述符上出現(xiàn)第二次可讀寫事件才會通知你!!!這種模式比水平觸發(fā)效率高,系統(tǒng)不會充斥大量你不關心的就緒文件描述符!!!
?
IOCP(AIO)
微軟在 Winsocket2 中引入了 IOCP(Input/Output Completion Port)模型。IOCP 是 Input/Output Completion Port(I/O 完成端口)的簡稱。簡單的說,IOCP 是一種高性能的 I/O 模型,是一種應用程序使用線程池處理異步 I/O 請求的機制。Java7 中對 IOCP 有了很好的封裝,程序員可以非常方便的時候經(jīng)過封裝的 channel 類來讀寫和傳輸數(shù)據(jù)。
不僅和epoll一樣接收到Socket的事件,并且接收時OS已經(jīng)完成了IO,不需要在應用層進行IO。
?
首先我們創(chuàng)建一個完成端口 CreateIOCompletionPort,然后再創(chuàng)建一個或多個工作線程,并指定它們到這個完成端口上去讀取數(shù)據(jù)。再將遠程連接的套接字句柄關聯(lián)到這個完成端口。工作線程調用 getQueuedCompletionStatus 方法在關聯(lián)到這個完成端口上的所有套接字上等待 I/O 的完成,再判斷完成了什么類型的 I/O,然后接著發(fā)出 WSASend 和 WSARecv,并繼續(xù)下一次循環(huán)阻塞在 getQueuedCompletionStatus。
?
具體的說,一個完成端口大概的處理流程包括:
?
創(chuàng)建一個完成端口;
Port port = createIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, fixedThreadCount());
創(chuàng)建一個線程 ThreadA;
ThreadA 線程循環(huán)調用 GetQueuedCompletionStatus 方法來得到 I/O 操作結果,這個方法是一個阻塞方法;
?While(true){
?????? ?getQueuedCompletionStatus(port, ioResult);
?}
主線程循環(huán)調用 accept 等待客戶端連接上來;
主線程 accept 返回新連接建立以后,把這個新的套接字句柄用 CreateIoCompletionPort 關聯(lián)到完成端口,然后發(fā)出一個異步的 Read 或者 Write 調用,因為是異步函數(shù),Read/Write 會馬上返回,實際的發(fā)送或者接收數(shù)據(jù)的操作由操作系統(tǒng)去做。
?if (handle != 0L) {
?????? ?createIoCompletionPort(handle, port, key, 0);
?}
主線程繼續(xù)下一次循環(huán),阻塞在 accept 這里等待客戶端連接。
操作系統(tǒng)完成 Read 或者 Write 的操作,把結果發(fā)到完成端口。
ThreadA 線程里的 GetQueuedCompletionStatus() 馬上返回,并從完成端口取得剛完成的 Read/Write 的結果。
在 ThreadA 線程里對這些數(shù)據(jù)進行處理 ( 如果處理過程很耗時,需要新開線程處理 ),然后接著發(fā)出 Read/Write,并繼續(xù)下一次循環(huán)阻塞在 GetQueuedCompletionStatus() 這里。
?
分區(qū)
磁盤的文件名
Linux 中每個硬件都被當做一個文件。
常見磁盤的文件名:
SCSI/SATA/USB 磁盤:/dev/sd[a-p]
IDE 磁盤:/dev/hd[a-d]
其中文件名后面的序號的確定與磁盤插入的順序有關,而與磁盤所插入的插槽位置無關。
Linux系統(tǒng)使用字母和數(shù)字的組合來指代硬盤分區(qū),Linux系統(tǒng)使用一種更加靈活的命名方案,該命名方案是基于文件的,文件名的格式為/dev/xxyN,
/dev/:這是Linux系統(tǒng)下所有設備文件所在的目錄名。
xx:分區(qū)名的前兩個字母表示分區(qū)所在設備的類型,通常是hd(IDE硬盤)或sd(SCSI硬盤)。
y:這個字母表示分區(qū)所在的設備。
N:最后的數(shù)字N代表分區(qū)。
掛載目錄:
Linux系統(tǒng)處理分區(qū)及磁盤存儲的方法與Windows截然不同,Linux系統(tǒng)中的每一個分區(qū)都是構成支持一組文件和目錄所必需的存儲區(qū)的一部分。它是通過掛載來實現(xiàn)的,掛載是將分區(qū)關聯(lián)到某一目錄的過程,掛載分區(qū)使起始于這個指定目錄(通稱為掛載目錄)的存儲區(qū)能夠被使用。
分區(qū)表
磁盤分區(qū)表主要有兩種格式,一種是限制較多的 MBR 分區(qū)表,一種是較新且限制較少的 GPT 分區(qū)表。
?
1. MBR
MBR 中,第一個扇區(qū)最重要,里面有:主要開機記錄(Master boot record, MBR)及分區(qū)表(partition table),其中 MBR 占 446 bytes,partition table 占 64 bytes。
?
分區(qū)表只有 64 bytes,最多只能存儲 4 個分區(qū),這 4 個分區(qū)為主分區(qū)(Primary)和擴展分區(qū)(Extended)。其中擴展分區(qū)只有一個,它將其它空間用來記錄分區(qū)表,可以記錄更多的分區(qū),因此通過擴展分區(qū)可以分出更多區(qū)分,這些分區(qū)稱為邏輯分區(qū)。
?
Linux 也把分區(qū)當成文件,分區(qū)文件的命名方式為:磁盤文件名+編號,例如 /dev/sda1。注意,邏輯分區(qū)的編號從 5 開始。
?
2. GPT
不同的磁盤有不同的扇區(qū)大小,例如 512bytes 和最新磁盤的 4k。GPT 為了兼容所有磁盤,在定義扇區(qū)上使用邏輯區(qū)塊地址(Logical Block Address, LBA)。
?
GPT 第 1 個區(qū)塊記錄了 MBR,緊接著是 33 個區(qū)塊記錄分區(qū)信息,并把最后的 33 個區(qū)塊用于對分區(qū)信息進行備份。
壓縮
tar [主選項+輔選項][文件或者目錄]
?
備份/root/abc目錄及其子目錄下的全部文件,備份文件名為abc.tar。
[root@PC-LINUX ~]# touch /root/abc/a /root/abc/b /root/abc/c
//在/root/abc目錄中創(chuàng)建/root/abc/a、/root/abc/b和/root/abc/c文件
[root@PC-LINUX ~]# tar cvf abc.tar /root/abc
?
查看abc.tar備份文件的內容,并顯示在顯示器上。
[root@PC-LINUX ~]# tar tvf abc.tar
?
將文件/root/abc/d添加到abc.tar包里面去。
[root@PC-LINUX ~]# touch /root/abc/d
[root@PC-LINUX ~]# tar rvf abc.tar /root/abc/d
?
更新原來tar包abc.tar中的文件/root/abc/d。
[root@PC-LINUX ~]# tar uvf abc.tar /root/abc/d
?
tar調用gzip
把/root/abc目錄包括其子目錄全部做備份文件,并進行壓縮,文件名abc.tar.gz。
[root@PC-LINUX ~]# tar zcvf abc.tar.gz /root/abc
?
查看壓縮文件abc.tar.gz的內容,并顯示在顯示器上。
[root@PC-LINUX ~]# tar ztvf abc.tar.gz
?
將壓縮文件abc.tar.gz解壓縮出來。
[root@PC-LINUX ~]# tar zxvf abc.tar.gz
?
tar調用bzip2
將目錄/root/abc及該目錄所有文件壓縮成abc.tar.bz2文件。
[root@PC-LINUX ~]# tar cjf abc.tar.bz2 /root/abc
?
查看壓縮文件abc.tar.bz2的內容,并顯示在顯示器上。
[root@PC-LINUX ~]# tar tjf abc.tar.bz2
?
將abc.tar.bz2文件解壓縮。
[root@PC-LINUX ~]# tar xjf abc.tar.bz2
?
總結
以上是生活随笔為你收集整理的Linux必懂知识大总结(下)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: leetcode180. 连续出现的数字
- 下一篇: linux 其他常用命令