Shell 管線(pipe)與重導向(redirect)完整解說
三個標準串流(Standard Streams)
在理解管線與重導向之前,必須先了解 Linux 的「三個標準串流」概念。每個 Linux 程式啟動時,都會自動連接三個資料流:
| 名稱 | 編號 | 說明 | 預設連到 |
|---|---|---|---|
| stdin 標準輸入 |
0 |
程式的資料輸入來源 | 鍵盤 |
| stdout 標準輸出 |
1 |
程式的正常輸出 | 終端機螢幕 |
| stderr 標準錯誤 |
2 |
程式的錯誤訊息輸出 | 終端機螢幕 |
鍵盤 ─── stdin (0) ──→ [ 程式 ] ──→ stdout (1) ─── 螢幕
└──→ stderr (2) ─── 螢幕
管線和重導向,就是改變這些串流的連接目標。
輸出重導向(>、>>)
把程式的標準輸出(stdout)從螢幕改寫到檔案:
單箭頭 >:覆寫模式
建立或覆蓋目標檔案,寫入程式的輸出:
$ ls /etc/ > filelist.txt
(不顯示,ls 的輸出被寫進 filelist.txt)
$ cat filelist.txt
apt
bash.bashrc
cron.d
hosts
nginx
passwd
...
> 會覆蓋已存在的檔案內容,操作前確認檔案是否重要。若要保留原有內容,改用 >>。
雙箭頭 >>:附加模式
將輸出附加到檔案末尾,不覆蓋原有內容:
$ echo "$(date): 腳本執行開始" >> deploy.log
$ echo "$(date): 腳本執行結束" >> deploy.log
$ cat deploy.log
Tue May 20 10:00:00 CST 2026: 腳本執行開始
Tue May 20 10:00:05 CST 2026: 腳本執行結束
輸入重導向(<)
把程式的標準輸入(stdin)從鍵盤改為讀取檔案:
$ sort < names.txt
Alice
Bob
Charlie
Dave
讓 sort 從 names.txt 讀取輸入,而非等待鍵盤輸入。
Here Document(Here-doc):<<
將多行文字直接寫進腳本作為輸入,不需要另建立檔案:
$ cat << 'EOF'
這是第一行
這是第二行
變數 $HOME 不會被展開(有引號)
EOF
這是第一行
這是第二行
變數 $HOME 不會被展開(有引號)
Here-doc 在腳本中很常用,例如建立設定檔、傳送 SQL 等。
錯誤輸出重導向(2>、2>&1)
stderr(錯誤訊息)和 stdout(正常輸出)是兩個不同的串流,需要分別處理:
只重導向錯誤訊息
$ ls /nonexistent 2> errors.txt
(螢幕無輸出,錯誤訊息寫進 errors.txt)
stdout 和 stderr 都重導向(最常用)
2>&1 表示「把 stderr(2)合併到 stdout(1)去」:
$ ./long-script.sh > output.log 2>&1
這樣正常輸出和錯誤訊息都寫進同一個日誌檔,是腳本中最常見的寫法。
更簡潔的寫法(bash 4+ 支援):
$ ./long-script.sh &> output.log
stdout 和 stderr 分開記錄
$ ./app.sh > app.log 2> error.log
丟棄輸出:/dev/null
/dev/null 是一個特殊的虛擬裝置,寫進去的資料都被丟棄,從它讀取永遠得到空資料。常用於屏蔽不需要的輸出:
$ ping -c 1 google.com > /dev/null 2>&1
如果只想知道 ping 是否成功(用回傳碼),不想看輸出,就重導向到 /dev/null。
$ if ping -c 1 -W 2 8.8.8.8 > /dev/null 2>&1; then
echo "網路正常"
else
echo "網路異常"
fi
管線(|):串聯指令
管線(pipe)用 | 符號,把前一個指令的 stdout 接到後一個指令的 stdin,讓多個指令協同工作:
指令A | 指令B | 指令C
stdout↗ stdout↗
stdin↗ stdin↗
最經典的範例:
$ cat /etc/passwd | grep "alice"
不過上面這個例子可以更簡潔地寫成:
$ grep "alice" /etc/passwd
管線真正的威力在於組合多個工具:
$ cat /etc/passwd | cut -d: -f1 | sort | head -5
_apt
alice
avahi
backup
bin
分解這個指令:
cat /etc/passwd:輸出 passwd 檔的所有內容cut -d: -f1:以:分隔,取第一欄(使用者名稱)sort:排序head -5:只取前 5 行
tee:分流輸出到螢幕和檔案
tee 指令讓輸出同時顯示在螢幕上,又寫進檔案,就像 T 形管接頭:
$ ls -la | tee listing.txt
(在螢幕顯示 ls 的輸出,同時寫進 listing.txt)
常見的應用:安裝套件時同時記錄日誌
$ sudo apt upgrade | tee upgrade-$(date +%Y%m%d).log
需要 sudo 寫入系統檔案時:
$ echo "192.168.1.10 myserver" | sudo tee -a /etc/hosts
實戰組合範例
範例 1:找出佔磁碟最多的 10 個目錄
$ du -sh /var/* 2>/dev/null | sort -rh | head -102.3G /var/log
1.2G /var/cache
850M /var/lib
範例 2:統計日誌中各 HTTP 狀態碼的數量
$ cat /var/log/nginx/access.log | awk '{print $9}' | sort | uniq -c | sort -rn 52340 200
3241 304
892 404
127 500
範例 3:找出佔用最多 CPU 的前 5 個程序
$ ps aux --sort=-%cpu | head -6USER PID %CPU %MEM VSZ RSS COMMAND
mysql 1234 5.2 15.3 1024000 314000 mysqld
nginx 5678 0.8 1.2 51200 24600 nginx: worker
範例 4:搜尋所有 .php 檔案中含有密碼的行
$ grep -rn "password\|passwd\|secret" --include="*.php" ./src/ 2>/dev/null | grep -v "//.*password"./src/config.php:15:$db_password = getenv('DB_PASS');
管線的概念是 Linux 命令列哲學的精髓。多練習用小工具組合成一行指令,你會發現 Linux 命令列極其強大。