Zsh 開發(fā)指南(第十三篇 管道和重定向)

導讀

到目前為止,我們已經(jīng)大致了解了 zsh 的語法特性缠劝,可以寫一些功能不復(fù)雜的腳本了妖泄。但 shell 腳本主要的應(yīng)用場景并不是閉門造車寫?yīng)毩⒌某绦颍呛屯獠凯h(huán)境交互客税。所以要寫出實用的腳本况褪,要了解 zsh 如何和外部環(huán)境交互。這里的外部環(huán)境包括其他進程更耻、文件系統(tǒng)测垛、網(wǎng)絡(luò)等等。本篇主要講管道和重定向秧均,這是和其他進程食侮、文件系統(tǒng)等交互的基礎(chǔ)号涯。

本文中的命令主要是為了演示管道的用法,在實際腳本中通常不需要使用這些命令锯七,因為可以用 zsh 代碼直接實現(xiàn)链快。另外本系列文章不詳細講任何外部命令的用法,因為相關(guān)文檔或者書籍特別多眉尸。如果看不懂本文的某些內(nèi)容域蜗,可以暫時跳過,基本不影響其余部分的理解噪猾。

管道

管道是類 Unix 系統(tǒng)中的一個比較基礎(chǔ)也特別重要的概念地消,它用于將一個程序的輸出作為另一個程序的輸入,進而兩個程序的數(shù)據(jù)可以互通畏妖。如果只是使用管道脉执,還是非常簡單易懂的,并不需要了解管道的實現(xiàn)細節(jié)戒劫。

管道的基本用法:

% ls
git  tmp
# wc -l 功能是計算輸入內(nèi)容的行數(shù)
% ls | wc -l
2

| 即管道半夷,在鍵盤上是主鍵盤區(qū)右側(cè) \ 對應(yīng)的上檔鍵字符。如果只輸入 wc -l迅细,wc 會等待用戶輸入巫橄,這時可以輸入字符串,然后回車繼續(xù)輸入茵典,直到按 ctrl + d 結(jié)束輸入湘换。然后 wc 會統(tǒng)計用戶一共輸入了多少行,然后輸出行數(shù)统阿。

# 敲 wc -l 回車后彩倚,依次按 a 回車 b 回車 ctrl + d
% wc -l
a
b
2

但如果前邊有個管道符號,ls | wc -l扶平,那么 wc 就不等待用戶輸入了帆离,而是直接將 ls 的結(jié)果作為輸入讀取過來,然后統(tǒng)計行數(shù)结澄,輸出結(jié)果哥谷。

關(guān)于管道的更多細節(jié)

我們再運行一個簡單的例子:

% cat | wc -l

# 查看 cat 進程打開的 fd
% ls -l /proc/$(pidof cat)/fd
total 0
lrwx------ 1 goreliu goreliu 0 2017-08-30 21:15 0 -> /dev/pts/1
l-wx------ 1 goreliu goreliu 0 2017-08-30 21:15 1 -> pipe:[2803]
lrwx------ 1 goreliu goreliu 0 2017-08-30 21:15 2 -> /dev/pts/1

# 查看 wc 進程打開的 fd
% ls -l /proc/$(pidof wc)/fd
total 0
lr-x------ 1 goreliu goreliu 0 2017-08-30 21:16 0 -> pipe:[2803]
lrwx------ 1 goreliu goreliu 0 2017-08-30 21:16 1 -> /dev/pts/1
lrwx------ 1 goreliu goreliu 0 2017-08-30 21:16 2 -> /dev/pts/1

cat 命令的效果是等待用戶輸入,等用戶輸入一行麻献,它就把這行再輸出來们妥,直到用戶按 ctrl - d。所以 cat | wc -l 也會等待用戶輸入勉吻。

我們看下 fd 的指向监婶,/dev/ps1/1 是指向偽終端設(shè)備文件的,進程就是通過這個來讀取用戶的輸入和輸出自己的內(nèi)容餐曼。0 是標準輸入(即用戶輸入端)压储,1 是標準輸出(即正常情況的輸出端)鲜漩,2 是錯誤輸出(即異常情況的輸出端)源譬。但是 cat 的輸出端指向了 一個管道集惋,并且 wc 的 輸入端指向了一個相同的管道,這代表兩個進程的輸入輸出端是通過管道連接的踩娘。這種管道是匿名管道刮刑,即只在內(nèi)核中存在,是沒有對應(yīng)的文件路徑的养渴。

重定向

重定向雷绢,指的便是 fd 的重定向,管道也是重定向的一種方法理卑。但用得更多的是將進程的 fd 重定向到文件翘紊。

一個最簡單的例子是輸出內(nèi)容到文件。

% echo abce > test.txt
% cat test.txt
abce

因為這個用法太常見了藐唠,大家可能習以為常了帆疟。我們依然來看下更多的細節(jié)。

% cat > test.txt

# 在另一個 zsh 中運行
% ls -l /proc/$(pidof cat)/fd
total 0
lrwx------ 1 goreliu goreliu 0 Aug 30 21:43 0 -> /dev/pts/1
l-wx------ 1 goreliu goreliu 0 Aug 30 21:43 1 -> /tmp/test.txt
lrwx------ 1 goreliu goreliu 0 Aug 30 21:43 2 -> /dev/pts/1

可以看到標準輸出已經(jīng)指向 test.txt 文件了宇立。

除了標準輸出可以重定向踪宠,標準輸入(fd 0),錯誤輸出(fd 2)也都可以妈嘹。

% touch 0.txt 1.txt 2.txt
% sleep 1000 <0.txt >1.txt 2>2.txt

# 在另一個 zsh 中運行
% ls -l /proc/$(pidof sleep)/fd
total 0
lr-x------ 1 goreliu goreliu 0 Aug 30 21:46 0 -> /tmp/0.txt
l-wx------ 1 goreliu goreliu 0 Aug 30 21:46 1 -> /tmp/1.txt
l-wx------ 1 goreliu goreliu 0 Aug 30 21:46 2 -> /tmp/2.txt

<0.txt 是重定向標準輸入柳琢,2>2.txt 是重定向錯誤輸出,>1.txt(即 1>1.txt)是重定向到標準輸出润脸。然后我們看到 3 個文件已經(jīng)各就各位柬脸,全部被重定向了。但因為 sleep 并不去讀寫任何東西毙驯,重定向它的輸入輸出沒有什么意義肖粮。

更多重定向的用法

一個 fd 只能重定向到一個文件,一一對應(yīng)尔苦。但在 zsh 中涩馆,我們可以把一個 fd 對應(yīng)到多個文件。

% cat >0.txt >1.txt >2.txt

輸入完成后允坚,3 個文件的內(nèi)容都更新了魂那,這是怎么回事呢?

其實是 zsh 進程做了中介稠项。

% pstree -p | grep cat
        `-tmux: server(1172)-+-zsh(1173)---cat(1307)---zsh(1308)

% ls -l /proc/1307/fd
total 0
lrwx------ 1 goreliu goreliu 0 Aug 30 21:57 0 -> /dev/pts/1
l-wx------ 1 goreliu goreliu 0 Aug 30 21:57 1 -> pipe:[2975]
lrwx------ 1 goreliu goreliu 0 Aug 30 21:57 2 -> /dev/pts/1

% ls -l /proc/1308/fd
total 0
l-wx------ 1 goreliu goreliu 0 Aug 30 21:58 12 -> /tmp/0.txt
l-wx------ 1 goreliu goreliu 0 Aug 30 21:58 13 -> /tmp/1.txt
lr-x------ 1 goreliu goreliu 0 Aug 30 21:58 14 -> pipe:[2975]
l-wx------ 1 goreliu goreliu 0 Aug 30 21:58 15 -> /tmp/2.txt

可以看到 cat 的標準輸出是重定向到管道了涯雅,管道對面是 zsh 進程,然后 zsh 打開了那三個文件展运。實際將內(nèi)容寫入文件的是 zsh活逆,而不是 cat精刷。但不管是誰寫入的,這個用法很方便蔗候。

標準輸入怒允、錯誤輸出也可以重定向多個文件。

% echo good >0.txt >1.txt >2.txt

% cat <0.txt <1.txt <2.txt
good
good
good

給 cat 的標準輸出重定向 3 個文件锈遥,它將 3 個文件的內(nèi)容全部讀取了出來纫事。

除了能同時重定向 fd 到多個文件外,還可以同時重定向到管道和文件所灸。

# 敲完 a b c 后 ctrl -d 退出
% cat >0.txt >1.txt | wc -l
a
b
c
3

% cat 0.txt 1.txt
a
b
c
a
b
c

可以看到輸入的內(nèi)容寫入了文件丽惶,并且通過管道傳給了 wc -l,不用說爬立,這又是 zsh 在做背后工作钾唬,將數(shù)據(jù)分發(fā)給了文件和管道。所以在 zsh 中是不需要使用 tee 命令的侠驯。

命名管道

除了匿名管道抡秆,我們還可以使用命名管道,這樣更容易控制陵霉。命名管道所使用的文件即 FIFO(First Input First Output琅轧,先入先出)文件。

# mkfifo 用來創(chuàng)建 FIFO 文件
% mkfifo fifo
% ls -l
prw-r--r-- 1 goreliu goreliu 0 2017-08-30 21:29 fifo|

# cat 寫入 fifo
% cat > fifo

# 打開另一個 zsh踊挠,運行 wc -l 讀取 fifo
% wc -l < fifo

然后在 cat 那邊輸入一些內(nèi)容乍桂,按 ctrl - d 退出,wc 這邊就會統(tǒng)計輸入的行數(shù)效床。

在輸入完成之前睹酌,我們也可以看一下 cat 和 wc 兩個進程的 fd 指向哪里:

% ls -l /proc/$(pidof cat)/fd
total 0
lrwx------ 1 goreliu goreliu 0 Aug 30 21:35 0 -> /dev/pts/2
l-wx------ 1 goreliu goreliu 0 Aug 30 21:35 1 -> /tmp/fifo
lrwx------ 1 goreliu goreliu 0 Aug 30 21:35 2 -> /dev/pts/2

% ls -l /proc/$(pidof wc)/fd
total 0
lr-x------ 1 goreliu goreliu 0 Aug 30 21:34 0 -> /tmp/fifo
lrwx------ 1 goreliu goreliu 0 Aug 30 21:34 1 -> /dev/pts/1
lrwx------ 1 goreliu goreliu 0 Aug 30 21:34 2 -> /dev/pts/1

可以看到之前的匿名管道已經(jīng)變成了我們剛剛創(chuàng)建的 fifo 文件,其他的并無不同剩檀。

exec 命令的用法

說起重定向憋沿,就不得不提 exec 命令。exec 命令主要用于啟動新進程替換當前進程以及對 fd 做一些操作沪猴。

用 exec 啟動新進程:

% exec cat

看上去效果和直接運行 cat 差不多辐啄。但如果運行 ctrl + d 退出 cat,終端模擬器就關(guān)閉了运嗜,因為在運行 exec cat 的時候壶辜,zsh 進程將已經(jīng)被 cat 取代了,回不去了担租。

但在腳本中很少直接這樣使用 exec砸民,更多情況是用它來操作 fd:

# 將當前 zsh 的錯誤輸出重定向到 test.txt
% exec 2>test.txt
# 隨意敲入一個不存在的命令,錯誤提示不出現(xiàn)了
% fdsafds
# 錯誤提示被重定向到 test.txt 里
% cat test.txt
zsh: command not found: fdsafds

更多用法:

用法 功能
n>filename 重定向 fd n 的輸出到 filename 文件
n<filename 重定向 fd n 的輸入為 filename 文件
n<>filename 同時重定向 fd n 的輸入輸出為 filename 文件
n>&m 重定向 fd n 的輸出到 fd m
n<&m 重定向 fd n 的輸入為 fd m
n>&- 關(guān)閉 fd n 的輸出
n<&- 關(guān)閉 fd n 的輸入

更多例子:

# 把錯誤輸出關(guān)閉,這樣錯誤內(nèi)容就不再顯示
% exec 2>&-
% fsdafdsa

% exec 3>test.txt
% echo good >&3
% exec 3>&-
# 關(guān)閉后無法再輸出
% echo good >&3
zsh: 3: bad file descriptor

% exec 3>test.txt
# 將 fd 4 的輸出重定向到 fd 3
% exec 4>&3
% echo abcd >&4
# 輸出內(nèi)容到 fd 4岭参,test.txt 內(nèi)容更新了
% cat test.txt
abcd

通常情況我們用 exec 主要為了重定向輸出和關(guān)閉輸出反惕,比較少操作輸入。

總結(jié)

本文講了管道和重定向的基本概念和各種用法演侯。Zsh 中的重定向還是非常靈活好用的姿染,之后的文章會詳細講在實際場景中怎樣使用。

參考

http://adelphos.blog.51cto.com/2363901/1601563

更新歷史

20170901:增加“exec 命令的用法”蚌本。

本文不再更新盔粹,全系列文章在此更新維護:github.com/goreliu/zshguide

付費解決 Windows隘梨、Linux程癌、Shell、C轴猎、C++嵌莉、AHK、Python捻脖、JavaScript锐峭、Lua 等領(lǐng)域相關(guān)問題,靈活定價可婶,歡迎咨詢沿癞,微信 ly50247。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末矛渴,一起剝皮案震驚了整個濱河市椎扬,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌具温,老刑警劉巖蚕涤,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異铣猩,居然都是意外死亡揖铜,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進店門达皿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來天吓,“玉大人,你說我怎么就攤上這事峦椰×淠” “怎么了?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵们何,是天一觀的道長萄焦。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么拂封? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任茬射,我火速辦了婚禮,結(jié)果婚禮上冒签,老公的妹妹穿的比我還像新娘在抛。我一直安慰自己,他們只是感情好萧恕,可當我...
    茶點故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布刚梭。 她就那樣靜靜地躺著,像睡著了一般票唆。 火紅的嫁衣襯著肌膚如雪朴读。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天走趋,我揣著相機與錄音衅金,去河邊找鬼。 笑死簿煌,一個胖子當著我的面吹牛氮唯,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播姨伟,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼惩琉,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了夺荒?” 一聲冷哼從身側(cè)響起瞒渠,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎般堆,沒想到半個月后在孝,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡淮摔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年私沮,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片和橙。...
    茶點故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡仔燕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出魔招,到底是詐尸還是另有隱情晰搀,我是刑警寧澤,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布办斑,位于F島的核電站外恕,受9級特大地震影響杆逗,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鳞疲,卻給世界環(huán)境...
    茶點故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一罪郊、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧尚洽,春花似錦悔橄、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至潮酒,卻和暖如春睛挚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背澈灼。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工竞川, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留店溢,地道東北人叁熔。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像床牧,于是被迫代替她去往敵國和親荣回。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,728評論 2 351

推薦閱讀更多精彩內(nèi)容

  • 本文筆記源自這里——[實驗樓]歡迎大家在下面交流其中有問題的地方喜歡請點收藏戈咳,每日更新(全部已親自實踐). 一. ...
    東皇Amrzs閱讀 3,977評論 7 54
  • 一心软、實驗介紹 1.1 實驗內(nèi)容 你可能對重定向這個概念感到些許陌生,但你應(yīng)該在前面的課程中多次見過>或>>操作了著蛙,...
    harrytc閱讀 693評論 0 0
  • tr删铃,tee 程序的IO 簡單的說程序由指令(命令)和數(shù)據(jù)(操作對象)組成,在linux上一切皆文件踏堡,程序操作對象...
    香吉矢閱讀 690評論 0 1
  • linux資料總章2.1 1.0寫的不好抱歉 但是2.0已經(jīng)改了很多 但是錯誤還是無法避免 以后資料會慢慢更新 大...
    數(shù)據(jù)革命閱讀 12,149評論 2 34
  • 總是喜歡懷念過往猎唁,過往的人和事。好的壞的顷蟆。诫隅。。帐偎!一直問自己是不是已經(jīng)老了逐纬,這么懷念從前,總想回到過去削樊。過去的一切似...
    如若錯過閱讀 110評論 0 0