簡體   English   中英

grep當前目錄下所有.h和.c文件中的關鍵字,但不包括兩個目錄

[英]grep a keyword in all .h and .c files under current directory but exclude two directories

我想在當前目錄下的所有.h.c文件中grep一個關鍵字./但在輸出中排除兩個目錄./stubdom./dist

我搜查,試過並測試了幾個命令; 最后我認為一個shell工作:

 find . -type d \( -path "./stubdom/*" -o -path "./dist/*" \) -prune -o -regex '.*\.\(h\|c\)$'  -print | xargs grep map_foreign_range

此shell正在查找所有.h和.c文件並排除./stubdom/和./dist路徑:

 find . -type d \( -path "./stubdom/*" -o -path "./dist/*" \) -prune -regex '.*\.\(h\|c\)$'  -print | xargs grep map_foreign_range

但是,上面的命令不起作用!

(我在正則表達式之前刪除-o以獲得AND操作!)

但是,我不太明白為什么會這樣。 我有幾個問題:

  1. \\( -path "./stubdom/*" -o -path "./dist/*" \\)這是一個find的動作,但它是如何工作的? 為什么它不是\\( -path "./stubdom/*" -o -path "./dist/*" -o \\) (我在末尾添加了另一個-o)。

  2. 如果我把-regex的前-type ,它會打印出.o文件,這意味着你-regex如果它之前把不工作-type 我的問題是:find命令的選項有從左到右的執行順序?

  3. 有沒有更簡潔的方法來實現我的目標:在當前目錄下的所有.h.c文件中grep一個關鍵字,但排除兩個目錄?

  1. -o運算符是'或'運算符。 第二條路徑之后的-o需要在它之后進行另一次測試。 帶括號的表達式也受條件-type d-prune約束。 總的來說,該術語表示'如果當前名稱是目錄,並且路徑與路徑表達式匹配,那么搜索將被修剪',這意味着搜索不會繼續

  2. find的一般操作是它搜索目錄列表,並對搜索表達式求值為true的目錄下找到的每個名稱執行某些操作。

    您當前的命令是:

     find . -type d \\( -path "./stubdom/*" -o -path "./dist/*" \\) -prune -o -regex '.*\\.\\(h\\|c\\)$' -print 

    我要放棄這個find . 部分,將其視為其余答案的假設。 我還將使用名稱AB代替stubdomdist來縮短它,以便一切都可見。

    我們當然可以通過用-name替換-regex來簡化它:

     -type d \\( -path "./A/*" -o -path "./B/*" \\) -prune -o -name '*.[ch]' -print 

    請注意,條件之間的默認連接是'和'。 使用C或shell表示法&&|| ,我們可以看到表達式的形式如下:

     (-type d && ( ... ) && -prune) || (-name '*.[ch]' && -print) 

    當您在-type之前移動-regex (現在為-name )時,將表達式重寫為:

     (-name '*.[ch]' && -type d && ( ... ) && -prune) || (-print) 

    因此,出現目標文件名的原因是無條件地應用了打印。

  3. 我的實驗表明, -path上的/*是適得其反的。

要演示,創建一個垃圾目錄, cd進入它,然后運行:

mkdir a b c d
for d in a b c d
do
    for file in abc def pqr zyz
    do
        for ext in c h
        do cp /dev/null $d/$file.$ext
        done
    done
done

現在運行:

find . -name '*.[ch]' | wc -l

這給出了答案32。

現在運行:

find . -type d \( -path "./a/*" -o -path "./b/*" \) -prune -o -name '*.[ch]' -print | wc -l

這也給出了32。

刪除-path操作數的/*部分,然后得到16.刪除wc顯示16個名稱是cd下的文件,這些是需要的文件。

find . -type d \( -path "./a" -o -path "./b" \) -prune -o -name '*.[ch]' -print

因此,應用於您的場景,您應該能夠使用:

find . -type d \( -path "./stubdom" -o -path "./dist" \) -prune -o -name '*.[ch]' -print

但是,您最好完全避免使用xargs

find . -type d \( -path "./a" -o -path "./b" \) -prune -o -name '*.[ch]' \
     -exec grep map_foreign_range {} +

如果任何文件名或目錄名包含空格(或制表符或換行符),則可以避免出現問題。 您也可以解決,隨着-print0足月find-0選項xargs ,如果您對這些命令的版本支持的符號(GNU做,也是如此的Mac OS X,因此可能是其他BSD變體也是如此)。

測試在Mac OS X 10.9.1完成與系統(BSD) find ,不與GNU find 。)

在這里,我會盡力回答你:

  1. 我不確定你為什么要在最后添加另一個-o 如果任何-path "./stubdom/*"-path "./dist/*" ,則行\\( -path "./stubdom/*" -o -path "./dist/*" \\)將被評估為True -path "./dist/*"將匹配。 -o是一個邏輯OR ,它是一個二元運算符,所以它需要兩個參數。 如果沒有別的,你不能在最后附加它。
  2. 你可能忘了移動-o 如果你沒有在-type d-regex ...之間放置一個OR -regex ... find將只查找與regexp匹配的目錄。 而不是任何目錄匹配正則表達式的東西。 順便說一句,是的,因為找到選項的順序絕對相關。
  3. 我認為你的解決方案已經足夠好了。

總結你的線如何工作,它等同於這個偽代碼:

if(isdir(file) and file != "./stubdom/*" and file != "./dist/*")
    print file;
else if (regex(file, '.*\.\(h\|c\)$' and file != "./stubdom/*" and file != "./dist/*")
    print file;

編輯:

閱讀我記得關於grep的--exclude-dir選項的評論。 試試吧。 它可能是更簡潔的解決方案。

  1. \\( -path "./stubdom/*" -o -path "./dist/*" \\)-prune的過濾器,因此應排除這些目錄。 它不能是\\( -path "./stubdom/*" -o -path "./dist/*" -o \\) ,這可能是一個錯誤。
  2. 如果你這樣做, find實際搜索,所以匹配約束被丟棄。
  3. grep還有排除文件的選項(例如--exclude-dir等)。

您還可以嘗試以下命令:

find | awk '(! (/stubdom\// || /dist\//)) && /\.(c|h)$/ {
    r=system ("grep -q map_foreign_range "$0)
    if(!r) print
}'

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM