Find

怎麼找。-type f -print -o -name 。-o -prune 真的有效嗎?

  • April 18, 2022

作為背景,我git在 hp-ux 11.11 (11v1) 系統上使用。我正在做一個廣泛的 .gitignore 文件來排除許多文件。我的 .gitignore 基本上是“忽略所有內容,除了這些目錄,也忽略那些目錄下的這些模式”。確切地說,如何以及為什麼與問題不完全相關。

git add我的目標是確保在執行之前得到我期望得到的結果git add。為此,我使用git check-ignore.

我的方法通常是這樣的:

find test2 -type f -exec git check-ignore -v -n {} \; grep !

為清楚起見,儲存庫存在於根目錄 (/.git) 中(它實際上符號連結到 /baz/dev/myRepo/.git),所以我git status從 / 呼叫。我還從 / 呼叫 find ,以便路徑匹配git預期看到的內容以及操作匹配返回find的路徑格式。-exec

標準輸出如下所示:

.gitignore:208:!test2/backupScripts/**  test2/backupScripts/CV_PostJob.sh
.gitignore:208:!test2/backupScripts/**  test2/backupScripts/CV_PostJob.sh.old
.gitignore:208:!test2/backupScripts/**  test2/backupScripts/CV_PreJob.sh
.gitignore:208:!test2/backupScripts/**  test2/backupScripts/CV_PreJob.sh.old
.gitignore:208:!test2/backupScripts/**  test2/backupScripts/CV_ScanCheck.sh
.gitignore:208:!test2/backupScripts/**  test2/backupScripts/oldCH.txt
.gitignore:212:!test2/scripts/**        test2/scripts/deprecated/CommvaultBackupScript.sh
.gitignore:212:!test2/scripts/**        test2/scripts/deprecated/NetBackupScript.sh
.gitignore:212:!test2/scripts/**        test2/scripts/benchmark.sh
.gitignore:212:!test2/scripts/**        test2/scripts/migrateVolumeSync.sh
.gitignore:212:!test2/scripts/**        test2/scripts/test.sh
.gitignore:206:!test2/* test2/CommvaultBackupScript.sh
.gitignore:206:!test2/* test2/NetBackupScript.sh
.gitignore:206:!test2/* test2/benchmark.sh
.gitignore:206:!test2/* test2/test.sh

通常,這種技術效果很好,但是在某些情況下,諸如/test2/foo/test2/bar的目錄都包含大量文件,這些文件將被 .gitignore 中的模式排除:

#Ignore everything
*

#add back /test2
!test2
!test2/**
#reignore foo and bar
test2/foo
test2/bar

所以,核心問題是:我希望能夠在find test2 -exec git check-ignore不列舉 test2/foo 和 test2/bar 的情況下執行,並且不必編寫命令,find test2 -name foo -prune -o -name bar -prune -o -type f -exec git check-ignore {} \;尤其是對於忽略的子目錄可能超過十幾個的情況,實際上,我只是想驗證 test2/ 中的文件是否將被正確包含,然後再執行一次以驗證單個小子目錄,例如 test2/backupScripts。

最終,我想調整符合 POSIX 的命令find . -type f -print -o -name . -o -prune,以便它可以與 -exec 一起執行,以便 find 將路徑傳遞給 git check-ignore ,這些路徑是絕對的而不是相對的。但是,我不知道該命令是如何工作的。我可以確認它確實只掃描執行它的任何地方的根目錄。

我在沒有現代版本的 findutils 的限制下工作,並且該平台沒有明顯的 GNU findutils 可用性,因此 -maxdepth 選項不可用。

此外,/test2 是一個掛載點,因此從 test2 中為 /.git 的儲存庫執行 git 將需要修改 Git 的環境 ( export GIT_DISCOVERY_ACROSS_FILESYSTEM=1) 以啟用遍歷掛載點邊界(此時cd test2 && find . -type f -exec git check-ignore --no-index -v -n {} \; -o -name . -o -prune | grep !可以正常工作)。如果可能的話,我寧願不這樣做(對於系統上 Git 的其他用途)。

那麼,具體是如何find . -type f -print -o -name . -o -prune工作的呢?是否可以對其進行修改以將一個或多個點替換為一些能夠從 / 呼叫它的路徑規範?或者這是某種“魔術”(如:只有在按此順序提供選項時才能引發所需的行為)序列,當按此特定順序提供時執行特定功能?除了以多種語言重新發布此特定答案本身之外,對這個特定命令的Google搜尋似乎幾乎沒有返回其他結果:find without recursion

我試圖通過執行以下操作來解構這個特定命令的行為:

cd /
find test2 -type f -print -o -name . -o prune
#no output

cd /test2
find . -type f -print -o -name . -o -prune
#get files in CWD as expected

find . -type f -print 
#gives me all files and directories below this, as you would expect

find . -type f -print -o -name . 
#gives the same as the prior command

find . -name . 
#gives just the CWD entry (.)

find . -name . -o -prune 
#gives just the files and folders in CWD, including the (.) entry

cd /
find test2 -name test2 -o -prune 
#also gives the files and folders directly in test2, including test2 itself

find test2 -name test2 -o -prune -o -type f -print 
#no output

find test2 -name test2 -prune 
#returns just test2 itself

find test2 -type f -print -o -name test2 -prune 
#predictably gives no output, as test2 is pruned

find test2 -type f -print -o -name foo -prune 
#gives full directory list except for /test2/foo, as expected.

find test2 -type f -print -o -name "test2/*" -prune 
#gives full directory list, as a / will never be in the "base" name which find tests.

cd /
find test2/* -type f -print -o -prune 
#this is the closest, same as "find . -name . -o -prune" but with cd to test2 first.
find . -type f -print -o -name . -o -prune

是一種在目前目錄中而不是在子目錄中查找正常文件的更複雜的方法,而不是更規範的方法:

find . ! -name . -prune -type f

使用 GNU 實現find(或那些複製了 GNUfind-mindepth/ -maxdepth)也可以寫成:

find . -mindepth 1 -maxdepth 1 -type f

-mindepth在這種情況下是多餘的,因為無論如何-type f都會排除.(深度0))。

在:

find . -type f -print -o -name . -o -prune

.find將開始搜尋文件的文件。

.本身不是正常文件,因此不會列印,-o將測試第一個的正確部分。-name .匹配,因此表達式解析為 true 並且-prune不執行。因為整個find表達式包含-print作為動作謂詞的 a,所以即使整個表達式對該文件解析為 true,也不會隱式列印。

現在,因為.沒有被修剪,並且因為它是一個目錄,所以find將讀取它的內容並將表達式應用於其中的每個文件(排除 the...特殊條目)。

對於那些,對於類型為regular的文件,-print將執行。對於任何其他類型的文件,由於-name .無法匹配,-prune將被執行。對於那些目錄類型的文件,這意味著它find不會進入它們。

所以其中重要的事情是:

  • 列印正常f類型)文件
  • .(頂層)以外的目錄被修剪,所以 find 不會下降到子目錄中。

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