2017-03-15 64 views
0

我有一個input.txt文件與代表一些命令行的字符串行,每行有兩個輸入參數:卸下文件中包含匹配文件夾中的文件名

commands a b 
commands a c 
commands b c 
... 

而且我想刪除針對其存在的所有行匹配(輸出文件)在文件夾out。例如,假設只有文件out/a_b_outout/b_c_out存在。然後我想從input.txt中刪除第一行和第三行。

此外,在out中可能有數百萬個文件,所以我需要一種有效的方式來查找匹配。另一方面,input中的行數在數千個數量級上,更易於管理。

我試圖首先提取從輸入文件中的模式(例如cut -d " " -f 2-3 input.txt | sed -e 's/\ /_/g'),然後遍歷這些項和用grep等

我想知道是否有執行更快和更優雅的方式這個。謝謝!

回答

3

這可能適用於你的情況

while read c x y; 
do [ -f "out/${x}_${y}_out" ] || echo "$c" "$x" "$y" 
done < input 

會遍歷較短的輸入文件和過濾基於現有文件中的行;輸出將是找不到文件的命令。如果您的輸入文件格式不正確,您可能需要加強讀取命令。

0

除非您需要awk進行額外的處理,或者您需要保持輸入線完全按照空白字符,請考慮karakfa's helpful shell-only solution

awk解決方案:

既然可以有百萬計的文件在out/,建立文件名的索引是不是一種選擇,但可以推遲到外殼測試文件的存在。

這將是緩慢的,因爲對於每個輸入線路創建sh子進程,但也可以是可接受的以輸入幾千行的順序:

awk '{ fpath = "out/" $2 "_" $3 "_out"; if (1 == system("[ -f '" fpath "' ]")) print }' \ 
    input.txt > input.tmp.$$.txt && mv input.tmp.$$.txt input.txt 
0

看這個小的測試與AWK(如果AWK是遊戲),做相反的(只是用於測試):

$ cat file3 
commands a b 
commands a c 
commands b c 

$ ls -l *_out 
-rw-r--r-- 1 root root 0 Mar 15 04:02 a_b_out 
-rw-r--r-- 1 root root 0 Mar 15 04:05 b_c_out 

$ awk 'NR==FNR{a[$2 "_" $3 "_out"]=$0;next}($0 in a){print a[$0]}' file3 <(find . -maxdepth 1 -type f -printf %f\\n) 
commands b c 
commands a b 

含義,這倒命令應該給你你想要的結果:

$ awk 'NR==FNR{a[$2 "_" $3 "_out"]=$0;next}(!($0 in a)){print a[$0]}' inuutfile <(find . -maxdepth 1 -type f -printf %f\\n) >newfile 

您可以刪除maxdepth 1以進入所有子目錄。

該解決方案基於小輸入文件建立索引,而不是基於可能存在的數百萬個文件建立索引;因此預期性能足夠好。

將不匹配的結果發送到新文件將比連續覆蓋現有文件快得多。

你可以只newfile中搬過來的oldfile當您完成(mv newfile inputfile

+0

@retrot回答更新 - 現在應該罰款awk –

+0

雖然你不是從數百萬的文件中建立_index_,但你仍然在循環所有這些,這不是一個好主意。 – mklement0

相關問題