首頁 > shell教程 閱讀:0更新時間:2020-03-28 02:19:20

Linux Shell管道詳解

通過前面的學習,我們已經知道了怎樣從文件重定向輸入,以及重定向輸出到文件。shell 還有一種功能,就是可以將兩個或者多個命令(程序或者進程)連接到一起,把一個命令的輸出作為下一個命令的輸入,以這種方式連接的兩個或者多個命令就形成了管道(pipe)。

linux 管道使用豎線|連接多個命令,這被稱為管道符。Linux 管道的具體語法格式如下:

command1 | command2
command1 | command2 [ | commandN... ]

當在兩個命令之間設置管道時,管道符|左邊命令的輸出就變成了右邊命令的輸入。只要第一個命令向標準輸出寫入,而第二個命令是從標準輸入讀取,那么這兩個命令就可以形成一個管道。大部分的 Linux 命令都可以用來形成管道。
這里需要注意,command1 必須有正確輸出,而 command2 必須可以處理 command2 的輸出結果;而且 command2 只能處理 command1 的正確輸出結果,不能處理 command1 的錯誤信息。

為什么使用管道?

我們先看下面一組命令,使用 mysqldump(一個數據庫備份程序)來備份一個叫做 wiki 的數據庫:

mysqldump -u root -p '123456' wiki > /tmp/wikidb.backup
gzip -9 /tmp/wikidb.backup
scp /tmp/wikidb.backup username@remote_ip:/backup/mysql/

上述這組命令主要做了如下任務:
  • mysqldump 命令用于將名為 wike 的數據庫備份到文件 /tmp/wikidb.backup;其中-u-p選項分別指出數據庫的用戶名和密碼。
  • gzip 命令用于壓縮較大的數據庫文件以節省磁盤空間;其中-9表示最慢的壓縮速度最好的壓縮效果。
  • scp 命令(secure copy,安全拷貝)用于將數據庫備份文件復制到 IP 地址為 remote_ip 的備份服務器的 /backup/mysql/ 目錄下。其中username是登錄遠程服務器的用戶名,命令執行后需要輸入密碼。

上述三個命令依次執行。然而,如果使用管道的話,你就可以將 mysqldump、gzip、ssh 命令相連接,這樣就避免了創建臨時文件 /tmp/wikidb.backup,而且可以同時執行這些命令并達到相同的效果。

使用管道后的命令如下所示:

mysqldump -u root -p '123456' wiki | gzip -9 | ssh username@remote_ip "cat > /backup/wikidb.gz"

這些使用了管道的命令有如下特點:
  • 命令的語法緊湊并且使用簡單。
  • 通過使用管道,將三個命令串聯到一起就完成了遠程 mysql 備份的復雜任務。
  • 從管道輸出的標準錯誤會混合到一起。

上述命令的數據流如下圖所示: Linux Shell管道演示圖

重定向和管道的區別

乍看起來,管道也有重定向的作用,它也改變了數據輸入輸出的方向,那么,管道和重定向之間到底有什么不同呢?

簡單地說,重定向操作符>將命令與文件連接起來,用文件來接收命令的輸出;而管道符|將命令與命令連接起來,用第二個命令來接收第一個命令的輸出。如下所示:

command > file
command1 | command1

有些讀者在學習管道時會嘗試如下的命令,我們來看一下會發生什么:

command1 > command2

答案是,有時嘗試的結果將會很糟糕。這是一個實際的例子,一個 Linux 系統管理員以超級用戶(root 用戶)的身份執行了如下命令:

cd /usr/bin
ls > less

第一條命令將當前目錄切換到了大多數程序所存放的目錄,第二條命令是告訴 Shell 用 ls 命令的輸出重寫文件 less。因為 /usr/bin 目錄已經包含了名稱為 less(less 程序)的文件,第二條命令用 ls 輸出的文本重寫了 less 程序,因此破壞了文件系統中的 less 程序。

這是使用重定向操作符錯誤重寫文件的一個教訓,所以在使用它時要謹慎。

Linux管道實例

【實例1】將 ls 命令的輸出發送到 grep 命令:
[c.biancheng.net]$ ls | grep log.txt
log.txt
上述命令是查看文件 log.txt 是否存在于當前目錄下。

我們可以在命令的后面使用選項,例如使用-al選項:
[c.biancheng.net]$ ls -al | grep log.txt
-rw-rw-r--.  1 mozhiyan mozhiyan    0 4月  15 17:26 log.txt
管道符|與兩側的命令之間也可以不存在空格,例如將上述命令寫作ls -al|grep log.txt;然而我還是推薦在管道符|和兩側的命令之間使用空格,以增加代碼的可讀性。

我們也可以重定向管道的輸出到一個文件,比如將上述管道命令的輸出結果發送到文件 output.txt 中:
[c.biancheng.net]$ ls -al | grep log.txt >output.txt
[c.biancheng.net]$ cat output.txt
-rw-rw-r--.  1 mozhiyan mozhiyan    0 4月  15 17:26 log.txt

【實例2】使用管道將 cat 命令的輸出作為 less 命令的輸入,這樣就可以將 cat 命令的輸出每次按照一個屏幕的長度顯示,這對于查看長度大于一個屏幕的文件內容很有幫助。
cat /var/log/message | less

【實例3】查看指定程序的進程運行狀態,并將輸出重定向到文件中。
[c.biancheng.net]$ ps aux | grep httpd > /tmp/ps.output
[c.biancheng.net]$ cat /tem/ps.output
mozhiyan  4101     13776  0   10:11 pts/3  00:00:00 grep httpd
root      4578     1      0   Dec09 ?      00:00:00 /usr/sbin/httpd
apache    19984    4578   0   Dec29 ?      00:00:00 /usr/sbin/httpd
apache    19985    4578   0   Dec29 ?      00:00:00 /usr/sbin/httpd
apache    19986    4578   0   Dec29 ?      00:00:00 /usr/sbin/httpd
apache    19987    4578   0   Dec29 ?      00:00:00 /usr/sbin/httpd
apache    19988    4578   0   Dec29 ?      00:00:00 /usr/sbin/httpd
apache    19989    4578   0   Dec29 ?      00:00:00 /usr/sbin/httpd
apache    19990    4578   0   Dec29 ?      00:00:00 /usr/sbin/httpd
apache    19991    4578   0   Dec29 ?      00:00:00 /usr/sbin/httpd

【實例4】顯示按用戶名排序后的當前登錄系統的用戶的信息。
[c.biancheng.net]$ who | sort
mozhiyan :0           2019-04-16 12:55 (:0)
mozhiyan pts/0        2019-04-16 13:16 (:0)
who 命令的輸出將作為 sort 命令的輸入,所以這兩個命令通過管道連接后會顯示按照用戶名排序的已登錄用戶的信息。

【實例5】統計系統中當前登錄的用戶數。
[c.biancheng.net]$ who | wc -l
5

管道與輸入重定向

輸入重定向操作符<可以在管道中使用,以用來從文件中獲取輸入,其語法類似下面這樣:

command1 < input.txt | command2
command1 < input.txt | command2 -option | command3


例如,使用 tr 命令從 os.txt 文件中獲取輸入,然后通過管道將輸出發送給 sort 或 uniq 等命令:
[c.biancheng.net]$ cat os.txt
redhat
suse
centos
ubuntu
solaris
hp-ux
fedora
centos
redhat
hp-ux
[c.biancheng.net]$ tr a-z A-Z <os.txt | sort
CENTOS
CENTOS
FEDORA
HP-UX
HP-UX
REDHAT
REDHAT
SOLARIS
SUSE
UBUNTU
[c.biancheng.net]$ tr a-z A-Z <os.txt | sort | uniq
CENTOS
FEDORA
HP-UX
REDHAT
SOLARIS
SUSE
UBUNTU

管道與輸出重定向

你也可以使用重定向操作符>或>>將管道中的最后一個命令的標準輸出進行重定向,其語法如下所示:

command1 | command2 | ... | commandN > output.txt
command1 < input.txt | command2 | ... | commandN > output.txt


【實例1】使用 mount 命令顯示當前掛載的文件系統的信息,并使用 column 命令格式化列的輸出,最后將輸出結果保存到一個文件中。
[c.biancheng.net]$ mount | column -t >mounted.txt
[c.biancheng.net]$ cat mounted.txt
proc         on  /proc                  type  proc        (rw,nosuid,nodev,noexec,relatime)
sysfs        on  /sys                   type  sysfs       (rw,nosuid,nodev,noexec,relatime,seclabel)
devtmpfs     on  /dev                   type  devtmpfs    (rw,nosuid,seclabel,size=496136k,nr_inodes=124034,mode=755)
securityfs   on  /sys/kernel/security   type  securityfs  (rw,nosuid,nodev,noexec,relatime)
tmpfs        on  /dev/shm               type  tmpfs       (rw,nosuid,nodev,seclabel)
devpts       on  /dev/pts               type  devpts      (rw,nosuid,noexec,relatime,seclabel,gid=5,mode=620,ptmxmode=000)
tmpfs        on  /run                   type  tmpfs       (rw,nosuid,nodev,seclabel,mode=755)
tmpfs        on  /sys/fs/cgroup         type  tmpfs       (rw,nosuid,nodev,noexec,seclabel,mode=755)
#####此處省略部分內容#####

【實例2】使用 tr 命令將 os.txt 文件中的內容轉化為大寫,并使用 sort 命令將內容排序,使用 uniq 命令去除重復的行,最后將輸出重定向到文件 ox.txt.new。
[c.biancheng.net]$ cat os.txt
redhat
suse
centos
ubuntu
solaris
hp-ux
fedora
centos
redhat
hp-ux
[c.biancheng.net]$ tr a-z A-Z <os.txt | sort | uniq >os.txt.new
[c.biancheng.net]$ cat os.txt.new
CENTOS
FEDORA
HP-UX
REDHAT
SOLARIS
SUSE
UBUNTU

beylze編程學院,一個分享編程知識和seo優化知識的網站。跟著beylze一起學習,每天都有進步。

通俗易懂,深入淺出,一篇文章只講一個知識點。

文章不深奧,不需要鉆研,在公交、在地鐵、在廁所都可以閱讀,隨時隨地漲姿勢。

文章不涉及代碼,不燒腦細胞,人人都可以學習。

當你決定關注beylze(公眾號:beylze),你已然超越了90%的其他從業者!

相關文章

優秀教程

国产亚洲欧美日韩