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 備份的復雜任務。
- 從管道輸出的標准錯誤會混合到一起。
上述命令的數據流如下圖所示:
重定向和管道的區別
乍看起來,管道也有重定向的作用,它也改變了數據輸入輸出的方向,那么,管道和重定向之間到底有什么不同呢?
簡單地說,重定向操作符>將命令與文件連接起來,用文件來接收命令的輸出;而管道符|將命令與命令連接起來,用第二個命令來接收第一個命令的輸出。如下所示:
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
轉載於:http://c.biancheng.net/view/3131.html