Linux

find + grep 匹配時如何列印文件名

  • April 2, 2021

以下有用的查找命令,列印名稱標籤中的值

find /tmp -type f -name '*.xml' -exec grep -o -P '(?<=<Name>).*(?=</Name>)' {} \;

問題是如果我們在 /tmp 下有幾個 xml 文件,那麼我們永遠不知道哪個 xml 文件有 Name 標籤

或者換句話說,這個 find 語法將列印 Name 的值

但沒有 xml 文件名

請建議如何在 grep 匹配時列印文件名:

(?<=<Name>).*(?=</Name>)

要使用適當的 XML 解析器(這裡我使用xmlstarlet)來提取Name所有 XML 文件中的所有節點的值,這些文件.xml名後綴在以下或以下/tmp

find /tmp -type f -name '*.xml' -exec xmlstarlet sel -t -v '//Name' -nl {} + 

這不需要開始<Name>標記和相應的結束</Name>標記在同一行,也不需要Name節點沒有屬性,就像您的grep命令那樣。

要使用 輸出更多資訊xmlstarlet,例如目前正在處理的文件名,並且僅在文件實際上具有Name節點時才執行此操作,請將上述命令xmlstarlet中的呼叫替換為find

xmlstarlet sel -t -i '//Name' -o '### ' -f -o ':' -nl -v '//Name' -nl

這將輸出 XML 文件的路徑名,前綴### 和後綴:以及換行符,但前提是文件包含Name節點。之後是Name文件中每個節點的值。


使用grep

grep如果在命令行上給出了多個文件,將始終輸出包含匹配項的文件的文件名。如果只傳遞一個文件,則不會列印文件名。

要強制始終將文件名與實際匹配一起列印,請將/dev/null作為額外文件添加到 grep 中:

find /tmp -type f -name '*.xml' -exec grep -o -P '(?<=<Name>).*(?=</Name>)' {} /dev/null \;

或者,對於可能更少的 呼叫grep,請find -exec grep ... {} +改用:

find /tmp -type f -name '*.xml' -exec grep -o -P '(?<=<Name>).*(?=</Name>)' /dev/null {} +

至少 GNUgrep以及grepOpenBSD 和 FreeBSD 上也支持-H始終列印文件名的標誌,即使只給出一個文件。既然您使用了 ,那麼您可能無論如何grep -P都在使用 GNU 。grep

引用自:https://unix.stackexchange.com/questions/417948