read 是 Bash 內建命令,用於從標準輸入或指定檔案描述符讀取一行資料,並按分隔符分割賦值給變數。它是 Shell 腳本互動、配置檔解析、資料流處理的核心工具。本文全面解析 read 參數、變數賦值規則、計時輸入、分隔符控制、檔案處理模式與進階陷阱。
read [選項] [變數...]
REPLY 變數。-d 指定分隔符) 結束。| 參數 | 功能 | 範例/說明 |
|---|---|---|
-p PROMPT | 顯示提示訊息 (不換行),僅寫入標準錯誤 | read -p "Enter name: " name |
-t SECONDS | 超時秒數 (支援小數),超時返回 1,變數保持原值 | read -t 5 -p "Quick: " ans |
-n NCHARS | 讀取 N 字元即返回 (不等待換行) | read -n 1 -p "Press any key..." key |
-N NCHARS | 精確讀取 N 字元 (不處理分隔符/轉義) | read -N 4 buf |
-s | 靜默模式,不回顯輸入 (密碼輸入) | read -s -p "Password: " pass |
-r | 原始模式,不處理反斜線轉義 (預設會處理 \ 換行續行) | 幾乎總是應加 -r |
-d DELIM | 自訂行分隔符 (預設換行),可為多字元 | read -d ':' var |
-a ARRAY | 分割結果存入陣列而非標量變數 | read -a arr |
-u FD | 從指定檔案描述符讀取 (而非標準輸入 0) | exec 3< file; read -u 3 line |
-e | 啟用 Readline 編輯 (歷史、補全、游標移動),需互動終端 | read -e -p "Path: " path |
read a b c
# 輸入:one two three four five
# 結果:a="one", b="two", c="three four five" (多餘合併到最後一個)
read a b c
# 輸入:one two
# 結果:a="one", b="two", c="" (不足設空字串,不會等待)
# 配合 -a 陣列
read -a arr
# 輸入:one two three
# 結果:arr=("one" "two" "three"), ${arr[0]}="one"
#!/bin/bash
read -r -p "Enter your name: " name
echo "Hello, $name!"
read -r -s -p "Password: " pass1; echo
read -r -s -p "Confirm: " pass2; echo
if [[ "$pass1" == "$pass2" ]]; then
echo "Password set."
else
echo "Mismatch."
fi
#!/bin/bash
echo "Select: 1) Start 2) Stop 3) Restart"
read -r -t 10 -p "Choice [1]: " choice
choice=${choice:-1} # 超時或直接 Enter 預設 1
case $choice in
1) echo "Starting..." ;;
2) echo "Stopping..." ;;
3) echo "Restarting..." ;;
*) echo "Invalid." ;;
esac
# 解析 CSV 行 (IFS 臨時修改更通用,但 -d 適用單字元分隔)
IFS=',' read -r col1 col2 col3 <<< "value1,value2,value3"
# 解析 /etc/passwd 格式 (冒號分隔)
while IFS=: read -r user pass uid gid gecos home shell; do
echo "User: $user, Home: $home"
done < /etc/passwd
# 正確模式:保留前導/尾隨空格、不處理反斜線、正確處理最後一行無換行
while IFS= read -r line; do
echo "Processing: $line"
done < file.txt
# 錯誤模式:
# for line in $(cat file.txt) # 會按 IFS 分割單詞、丟失空格、展開通配符
# while read line; do ... # 會處理反斜線、丟失尾隨空格
exec 3< file1
exec 4< file2
while true; do
read -r -u 3 line1 || break
read -r -u 4 line2 || break
echo "File1: $line1 | File2: $line2"
done
exec 3<&-; exec 4<&- # 關閉 fd
# 讀取固定 100 位元組
read -N 100 -r data < binary.dat
# 讀取至 NUL 字元 (C 風格字串)
read -d '' -r cstr < binary.dat
| 陷阱 | 現象 | 解決 |
|---|---|---|
不加 -r | 反斜線被轉義:輸入 C:\path 變 C:path;行尾 \ 導致續行 | 永遠加 -r,除非刻意要轉義 |
| 管道右側變數不生效 | echo "val" | read var; echo $var 輸出空 (子 Shell) | 用 read var <<< "val" (Here String) 或 { echo "val"; read var; } (大括號群組) |
read 吞掉前導/尾隨空格 | 預設 IFS 含空格,會修剪 | IFS= read -r line (臨時清空 IFS) |
| 最後一行無換行符不被讀取 | while read line; do 忽略無換行尾行 | while IFS= read -r line || [[ -n $line ]]; do (檢查變數非空) |
| 提示訊息輸出到標準輸出干擾管道 | -p 寫入 stderr,但重導向時可能混淆 | 明確 read -p "Prompt: " var 2>/dev/tty 或分離邏輯 |
IFS=$' \t\n' (空格、製表、換行)。read 先按 IFS 分割,再賦值給變數。IFS= read -r line:清空 IFS → 不分割 → 整行賦值給 line (保留所有空格)。IFS=::單一分隔符 → 按冒號分割。# 將檔案所有行讀入陣列 (Bash 4+)
mapfile -t lines < file.txt
# 等效於
readarray -t lines < file.txt
# -t 移除尾隨換行符
# 適用於整檔案載入記憶體場景,比迴圈 read 快
精通 read 的參數組合、IFS 控制、檔案描述符操作與邊界情況處理,能編寫健壯、高效、符合預期的 Shell 互動與資料處理邏輯。