程序和硬件之間隔了一個內核,比如程序要想加載磁盤上的數據,那么需要內核來完成,將程序加載到內核的pagecache中(4k),然后用戶空間的所有程序都可以訪問這個pagecache,如果有程序修改了這個數據,那么就會標記位ditry
兩個程序可以打開相同的文件,但是每個程序的文件描述fd符會自動維護著指針,文件在內容中的數據是一份的
每個文件有多個文件描述符,每個文件描述符可以理解為一個指針,任何程序都有0、1、2文件描述符,0表示標準輸入、1表示標準輸出、2表示錯誤
cd /proc
進入內核映射目錄,可以看到內核的一些變量屬性都在里面掛載,每一個數字都是一個進程的id號,都被映射成了文件
$$是當前bash的pid(端口),也就是說當前命令行程序的端口號
除了$$還可以通過$BASHPID 來獲得

這兩個都可以獲取到,區別是第一個優先級高,第二個優先級低
進入到這個j進程之后,進入到fd可以看到程序的描述符
lsof -op $$可以看當前$$進程文件描述符的細節



就可以可看到這個進程的文件描述符的信息了

可以看到進程是一個文件,然后進程的屬性也是文件,一切皆文件
重定向不是命令,而是機制
0表示標準輸入,1表示標準輸出,那么我們可以使用重定向的方式對其進行修改,比如ls標準輸入是當前的目錄,表示輸出是控制臺,我們可以對其進行修改,如下所示:

如上所示我們將1標準輸出改為了1.txt,這樣ls的的輸出就不會到控制臺了,而是會到1.txt中,需要注意1和>之間必須緊密連接
>表示輸出
<表示輸入

我們可以將cat AA.JAVA的文件內容的標注輸出屏幕重定向到1.txt

輸入read a,它就會阻塞了,然后我們輸入一個內容,然后按換行符,read會換行符特別敏感,只要有換行符就表示read完成了。

如上所示echo $a的結果就是123了。說明a 的標準輸入是控制臺,我們可以對其進行改變

如上所示,我們將a的標準輸入改為了1.txt,我們輸出a的時候,只有1.txt的第一行,這是因為read對換行符敏感,一旦有換行符,就會賦值成功。
ls可以同時查看多個目錄

如上所示,ls分別查看了./和一個隨便寫的目錄,所以一個正常輸出,另外一個報錯了,我們可以使用重定向,對正常輸出的重定向到一個文件,對不正常輸出的重定向到另外一個文件中,如下所示:

如上所示流還是可以進行傳遞的

標準輸出流指向1.txt,而錯誤輸出流指向1,這樣錯誤的也會輸出到1.txt了,需要注意的是2>$ 1,如果沒有$會把1當作一個普通的文件看待。
如果ls ./ ./aaaa 2>& 1 1>1.txt就會有問題,因為2>& 1,此時1就是標準輸出流,那么就會錯誤輸出到控制臺,1> 1.txt就會將標準輸出流重定向到1.txt,所以就是錯誤的到控制臺,正確的到1.txt,所以需要注意順序。
管道 |
head -10 1.txt
可以顯示1.txt中的前10行
tail -10 1.txt
可以顯示1.txt中的后10行
head -10 1.txt | tail -1
可以顯示第10行
父子進程

通過pstree可以看到當前所有進程的進程樹,同時我們可以看到倒數第二行,我們當前所處的bash進程下面開啟了一個pstree進程,那么pstree進程就是bash的子進程,前面介紹過我們可以通過echo $$獲取到當前的進程pid,下面我們在當前的進程下面再開啟一個bash進程

我們可以看到,我們進入了bash下面的bash進程,那么此時的pid就和父的不一樣了,下面我們再通過pstree來看一下:

如下所示,我們是在bash進程下面開啟了bash進程,然后下面有pstree進程。要想退出當前的進程,可以輸入exit

我們當前是在bash進程中,那么我們就可以寫bash程序,比如之前的read a,還可以給傳輸賦值,如下所示:

但是需要注意當前的x是定義在當前的進程的,而子進程是獲取不到的。

這說明進程之間是隔離的,如果要想讓子進程獲取到父進程的,需要在父進程中進行export

如上所示,子進程就獲取到了
bash命令中還可以定義代碼塊,如下所示:

注意{}和代碼之間必須要有空格,一個代碼必須有;作為結束

如上代碼所示,{ x=200 ; echo "fuzhi" ; } | cat 這個表示給x賦值200,然后輸出fuzhi,輸出通過流傳遞給了cat,cat接收到之后輸出給標注輸出流控制臺,所以屏幕輸出fuzhi了
,但是此時輸出x就是100,而不是200
這是因為bash程序在執行的時候,首先發現了管道 | ,那么它會自動地將管道兩邊設置為子進程,所以x=200,只是在子進程中執行的,不會對父進程有任何影響,|具有進程間的流動能力,所以雖然是兩個子進程,但是也依然可以進行數據的流動
是不是真的開啟子進程呢,我們來驗證一下

如上所示,我們輸出管道左邊的進程號,發現確實和當前進程的pid號不一致,那么說明確實開啟了一個子進程。需要注意的是左邊不能使用echo $$,這是因為echo $$的優先級相對較高,這樣bash解釋執行的時候,就會先執行echo $$,然后才看到管道|,這樣echo $$的結果就是父進程pid了。
在父進程中:

開啟兩個子進程,左邊子進程輸出當前子進程的pid,然后讀取s,然后右進程接收左進程的輸入,然后輸出到控制臺,然后輸出右進程的PID,然后讀取y。
執行之后,我們可以看到只執行到左進程的read就阻塞了,下面我們看一下父進程中是否創建了這兩個子進程,如下所示:

如下所示,我們可以看到父進程27414下面有兩個子進程27754和27755,然后我們去每個進程中看看文件描述符:

我們可以看到,第一個左進程的標準輸出已經是管道了,而第二個右進程的標準輸入也是管道了,這樣就和之前對接起來了。
socket

如下所示,我們可以看到當前進程的文件描述符8的輸入和輸出都是socket了

虛擬文件系統
cd /就會進入到根目錄
然后ll就可以看到根目錄下面的目錄

在這個虛擬文件系統中有三個分區,1、2、3,如下所示:

使用df命令可以看到當前的目錄掛載到哪個分區中,其中/掛載到/dev/...中,那么/下面的所有子目錄也是掛在到/dev/...中的,而/boot是引導程序,它會掛在到/dev/sda1下面

通過這個就是說linux的目錄會掛載到虛擬的磁盤上。
一切皆文件,這個意思就是說,真實的目錄可以是文件,攝像頭也可以是文件,打印機也是文件,既然是文件那么就可以使用IO流了。文件是有類型的,常用的類型有:
1、-表示可執行的
2、d是目錄
3、b是塊設備(硬盤)
4、c是字符設備(鍵盤,socket)
5、p是管道
6、eventpoll,epoll的內存區域
7、l是連接的
從一個地方能夠讀數據,不受限制,想讀哪就讀哪,這個就是塊設備


我首先通過touch命令創建a.txt,然后通過ln可以建立一個a.txt的硬連接b.txt,然后通過stat命令看這兩個文件的詳細信息

可以看到兩個文件有相同的Inode。需要知道的是a.txt和b.txt雖然有不同的路徑,但是它們卻指向相同的物理地址,修改任意一份,另外一個打開之后,也會發生變化,刪除一個,另外一個沒有影響。

如上所示可以通過ln -s建立a.txt的軟連接c.txt,軟連接可以理解為指向了a.txt,所以一旦a.txt被刪除,那么c.txt也沒有意義了。

如果看二者的Inode我們可以看到二者已經不一樣了,修改任意一方,另外一方也會有任何變化