如何使用while循環從兩個輸入文件中讀取
我想知道是否有任何方法可以從嵌套的 while 循環中的兩個輸入文件一次讀取一行。例如,假設我有兩個文件
FileA
和FileB
.檔案A:
[jaypal:~/Temp] cat filea this is File A line1 this is File A line2 this is File A line3
文件B:
[jaypal:~/Temp] cat fileb this is File B line1 this is File B line2 this is File B line3
目前範例腳本:
[jaypal:~/Temp] cat read.sh #!/bin/bash while read lineA do echo $lineA while read lineB do echo $lineB done < fileb done < filea
執行:
[jaypal:~/Temp] ./read.sh this is File A line1 this is File B line1 this is File B line2 this is File B line3 this is File A line2 this is File B line1 this is File B line2 this is File B line3 this is File A line3 this is File B line1 this is File B line2 this is File B line3
問題和期望的輸出:
對於 FileA 中的每一行,這將在 FileB 上完全循環。我嘗試使用 continue、break、exit,但它們都不是為了實現我正在尋找的輸出。我希望腳本從文件 A 中讀取一行,然後從文件 B 中讀取一行,然後退出循環並繼續讀取文件 A 的第二行和文件 B 的第二行。類似於以下腳本的內容 -
[jaypal:~/Temp] cat read1.sh #!/bin/bash count=1 while read lineA do echo $lineA lineB=`sed -n "$count"p fileb` echo $lineB count=`expr $count + 1` done < filea [jaypal:~/Temp] ./read1.sh this is File A line1 this is File B line1 this is File A line2 this is File B line2 this is File A line3 this is File B line3
這可以通過while循環實現嗎?
如果您可以保證某些字元永遠不會出現在第一個文件中,那麼您可以使用 paste。
例如,您肯定知道這
@
永遠不會發生:paste -d@ file1 file2 | while IFS="@" read -r f1 f2 do printf 'f1: %s\n' "$f1" printf 'f2: %s\n' "$f2" done
請注意,如果保證字元不會出現在第一個文件中就足夠了。這是因為在填充最後一個變數時
read
會忽略。IFS
所以即使@
發生在第二個文件中也不會被拆分。使用一些 bash 功能可以說是更乾淨的程式碼並使用預設分隔符選項卡粘貼的範例:
while IFS=$'\t' read -r f1 f2 do printf 'f1: %s\n' "$f1" printf 'f2: %s\n' "$f2" done < <(paste file1 file2)
使用的 Bash 特性:ansi c 字元串(
$'\t'
) 和程序替換(<(...)
) 以避免子 shell 問題中的 while 循環。如果您不能確定任何字元都不會出現在兩個文件中,那麼您可以使用兩個文件描述符。
while true do read -r f1 <&3 || break read -r f2 <&4 || break printf 'f1: %s\n' "$f1" printf 'f2: %s\n' "$f2" done 3<file1 4<file2
沒有測試太多。可能會在空行上中斷。
文件描述符編號 0、1 和 2 已分別用於標準輸入、標準輸出和標準錯誤。3 及以上的文件描述符(通常)是免費的。bash 手冊警告不要使用大於 9 的文件描述符,因為它們是“內部使用的”。
請注意,打開的文件描述符會繼承給 shell 函式和外部程序。繼承打開文件描述符的函式和程序可以讀取(和寫入)文件描述符。在呼叫函式或外部程序之前,您應該注意關閉所有不需要的文件描述符。
這是與上述相同的程序,實際工作(列印)與元工作分開(從兩個文件中並行讀取)。
work() { printf 'f1: %s\n' "$1" printf 'f2: %s\n' "$2" } while true do read -r f1 <&3 || break read -r f2 <&4 || break work "$f1" "$f2" done 3<file1 4<file2
現在我們假設我們無法控制工作程式碼,並且無論出於何種原因,該程式碼都試圖從文件描述符 3 中讀取。
unknowncode() { printf 'f1: %s\n' "$1" printf 'f2: %s\n' "$2" read -r yoink <&3 && printf 'yoink: %s\n' "$yoink" } while true do read -r f1 <&3 || break read -r f2 <&4 || break unknowncode "$f1" "$f2" done 3<file1 4<file2
這是一個範例輸出。請注意,第一個文件的第二行是從循環中“竊取”的。
f1: file1 line1 f2: file2 line1 yoink: file1 line2 f1: file1 line3 f2: file2 line2
以下是在呼叫外部程式碼(或任何相關程式碼)之前關閉文件描述符的方法。
while true do read -r f1 <&3 || break read -r f2 <&4 || break # this will close fd3 and fd4 before executing anycode anycode "$f1" "$f2" 3<&- 4<&- # note that fd3 and fd4 are still open in the loop done 3<file1 4<file2