如何使用 sed、grep 或 awk 根據另一個文件中的行號將某些行保留在文件中
我有兩個文件。
File1
包含一些句子,並File2
包含我要保留的行號File1
。例如
File1
:He is a boy. She is a cook. Okay. She went to school. She is pretty.
File2
:1 4
輸出:
He is a boy. She went to school.
有沒有辦法使用 , 或 來做到
sed
這grep
一點awk
?我不想在這里手動寫行號。
我們可以將數字列表轉換為一系列命令,並在一次呼叫中將
sed
它們作為編輯腳本執行:sed``sed
sed 's/$/p/' lines.list | sed -n -f /dev/stdin file.txt
在這裡,第一個通過簡單地插入每行的末尾來
sed
創建一個sed
包含諸如 等命令的腳本1p
。然後將此腳本發送到管道之後的第二個,管道讀取它並將其與文本文件一起作為輸入應用。4p``p``sed``-f /dev/stdin
這將只需要讀取每個文件一次。
使用
awk
,將行號作為鍵讀入關聯數組,然後,在讀取另一個文件時,查看目前行號是否是先前在數組中作為鍵的行號之一:awk 'FNR == NR { lines[$0]; next } (FNR in lines)' lines.list file.txt
在
awk
中,特殊變數NR
和FNR
分別是到目前為止讀取的記錄(行)總數和目前文件中讀取的記錄(行)總數。如果NR
等於FNR
,我們從第一個輸入文件中讀取,我們使用目前行創建一個數組條目$0
,作為鍵(沒有給出值),並立即跳到下一行輸入。如果我們不是從目前行讀取,我們會測試
FNR in lines
以查看FNR
目前文件中的行號是否是數組中名為lines
. 如果是,將列印目前行。如果沒有其他工具的大力支持,該
grep
實用程序並不是真正為執行此類任務而設計的。它從內容匹配(或不匹配)給定模式的文本文件中提取行。因此,模式應該與行匹配,而不是行號。以下內容僅供娛樂,不應被視為如何實際解決此問題的建議。
您可以使用插入行號
grep
grep -n '.*' file.txt
這會在文件中所有行的開頭插入行號,緊隨其後
:
的是行的原始內容。然後,與
sed
解決方案一樣,我們可以修改模式文件以使其匹配這些特定數字的選擇:sed 's/.*/^&:/' lines.list
這將輸出諸如
^1:
and之類的正則表達式^4:
,每個表達式都匹配行首的特定行號。然後我們可以
grep
使用這些表達式(這裡借助程序替換)。最後,我們使用以下命令刪除臨時行號cut
:grep -n '.*' file.txt | grep -f <(sed 's/.*/^&:/' lines.list) | cut -d : -f 2-
…但這太做作了,甚至不能被認為是合理的解決方案。
上述每個解決方案都將始終按照它們在文本文件中出現的順序顯示選定的行。如果您想按行號文件中出現的順序輸出行,那麼您可以改用
ed
(或awk
,請參閱下文):sed 's/$/p/' lines.list | ed -s file.txt
同樣,我們從行號文件創建一個編輯腳本,只需
p
在每行的末尾添加即可。然後將該腳本作為命令輸入傳遞給
ed
編輯器,編輯器將命令按順序應用於文本文件。測試:
$ cat lines.list 4 1
$ sed 's/$/p/' lines.list | ed -s file.txt She went to school. He is a boy.
請注意,
ed
將整個文件讀入記憶體,就像下面的等效awk
程序一樣:awk 'NR == FNR { lines[FNR] = $0; next } { print lines[$0] }' file.txt lines.list
請注意,與以前的
awk
解決方案相比,輸入文件是切換的。這允許我們首先將文本文件逐行讀取到lines
數組中,然後在讀取帶有行號的文件時從中隨機選擇行。