Bash
如何將 find 和 grep 與循環和變數一起使用?
我在一個目錄中有一堆文件。
# ls -1 file1 file2 file3 file4 file5 file6 file7 file8 file9 file10
任務是查找早於
file5
. 我可以做的# find . ! -newer file5 ./file1 ./file2 ./file3 ./file4 ./file5
現在我有一個文件,其中對上述任何/所有內容的引用可能類似於
# logfile=log cat ${logfile} /var/log/app/file1 /var/log/app/file3 /var/log/app/file5
現在我只想列出那些早於 file5 並且也在日誌文件中的文件。所以結果列表將是:
file1 file3 file5
我嘗試像這樣從這些文件名中提取文件名,但它不起作用。
find . ! -newer file4 -exec bash -c 'for i in {}; do grep $i ${logfile}; done' \;
如果目錄是
/var/log/app
then 而不是find . ! -newer file5
runfind /var/log/app ! -newer /var/log/app/file5
。這樣, 的輸出find
將採用您在log
.
find
然後你可以只用一個過濾輸出grep
:find /var/log/app ! -newer /var/log/app/file5 | grep -xFf log
-x
導致grep
匹配整行;-F
告訴它將模式視為固定字元串;-f
從指定文件中讀取模式。這些選項是可移植的。或者(或者在目前工作目錄不是
/var/log/app
,但您想假裝它是的情況下)創建第二個日誌,因此其中的條目與./…
原始的一般格式相匹配find
:sed 's|^/var/log/app/|./|' log > log2
新日誌包含可用於過濾原始
find
命令輸出的相對路徑:find . ! -newer file5 | grep -xFf log2
筆記:
! -newer file5
並不意味著“比file5
”更早。此測試匹配file5
任何同樣舊的文件。- 附加選項/測試(例如
-maxdepth 1
,-type f
)可能有用。你的嘗試:
find . ! -newer file5 -exec bash -c 'for i in {}; do grep $i ${logfile}; done' \;
在許多方面存在缺陷或次優:
- 您將日誌文件視為數據,將路徑名
find
視為模式。如上所示,以相反的方式執行此操作要容易得多。- 在 inner 的上下文中
bash
,$i
並${logfile}
沒有被引用。它們應該被雙引號- 您嵌入
{}
了 shell 程式碼。一般來說,嵌入式{}
可以表現得像一個未引用的變數,但無論你如何引用它,都存在命令注入漏洞。所以情況更糟。- 您使用
-exec … \;
which 替換{}
為一個路徑名(而不是-exec … {} +
),但您仍然寫得for i in {}
好像您期望很多一樣。通常,內殼可能會將其代替的內容解釋{}
為多個單詞。也可以觸發文件名生成。這是上面提到的“就像一個未引用的變數”行為。所以一般來說,你可能會得到很多循環的“路徑名”,而不是你所期望的。logfile
不在環境中,因此內殼將擴展$logfile
為空字元串。您不希望外殼擴展它(使其具有與 embedding 類似的缺陷{}
)。