[英]Shell globbing exclude directory patterns
忽略可以與 shell glob 關聯使用的命令,我想完成從 glob 模式中排除所有目錄和子目錄中的特定目錄模式。
假設我有這個目錄結構:
+-- a
+-- a1
+-- assets
+-- a1-1
+-- a1-1.js
+-- a1-2
+-- a1-2.js
+-- a2
+-- a2.js
+-- b
+-- b1
+-- b1-2
+-- b1-2-3
+-- assets
+-- b1-2-3.js
+-- b.js
+-- c
+-- c.js
我想列出文件路徑中沒有assets
的所有 js 文件。
到目前為止我已經嘗試過:
$ shopt -s globstar extglob
$ ls ./**/!(assets)/**/*.js
上面的模式不僅實現了它的目標,它甚至顯示了重復的輸出。 我知道我可以做這樣的事情:
$ ls ./**/*.js | grep -v "assets"
或者任何其他可以通過管道傳輸的命令,我只想要一個純 shell glob 模式。
預期輸出:
a/a2/a2.js
b/b.js
c/c.js
邁克爾的回答是對的。 **
匹配太多(貪婪匹配),包括assets
。
所以,有了這棵樹:
.
|-- a
| |-- a1
| | +-- assets
| | |-- a1-1
| | | +-- a1-1.js
| | +-- a1-2
| | +-- a1-2.js
| +-- a2
| +-- a2.js
|-- assets
| +-- xyz.js
|-- b
| |-- b1
| | +-- b1-2
| | +-- b1-2-3
| | |-- assets
| | | +-- b1-2-3.js
| | +-- test
| | |-- test2
| | | +-- test3
| | | +-- test4
| | | +-- test4.js
| | +-- test.js
| +-- b.js
|-- c
| +-- c.js
+-- x.js
.js 文件是:
$ find . -name '*.js'
./x.js
./assets/xyz.js
./a/a2/a2.js
./a/a1/assets/a1-2/a1-2.js
./a/a1/assets/a1-1/a1-1.js
./c/c.js
./b/b.js
./b/b1/b1-2/b1-2-3/test/test2/test3/test4/test4.js
./b/b1/b1-2/b1-2-3/test/test.js
./b/b1/b1-2/b1-2-3/assets/b1-2-3.js
有一個 bash 變量GLOBIGNORE
可以完全按照您的要求進行操作。
所以,這會起作用:
$ GLOBIGNORE='**/assets/**:assets/**:**/assets'
$ ls -1 **/*.js
a/a2/a2.js
b/b1/b1-2/b1-2-3/test/test2/test3/test4/test4.js
b/b1/b1-2/b1-2-3/test/test.js
b/b.js
c/c.js
x.js
問題是**
在您的情況下匹配太多或太少。 特別是!(assets)
前面的**
將匹配a1/assets/
,然后!(assets)
將匹配a1-1
,后面的**
將不匹配任何內容,因此整體匹配成功。
考慮這個簡化的例子:
touch a/a1/x.js a/a2/y.js a/a3/z.js
ls ./*/!(a2)/*.js
ls ./**/!(a2)/**/*.js
第一個ls
按預期工作,第二個沒有。
這可能是您開始使用zsh
的最佳時機 :-) 只需使用~
即可刪除匹配項:
% setopt extended_glob
% ls -1 **/*.js~*assets*
a/a2/a2.js
b/b.js
c/c.js
如果這是您經常搜索的內容,那么我只會編寫一個簡單的腳本。
對於測試,設置文件和目錄,如問題中所述:
(注意添加 c/assets.js 來測試邊緣案例) :
mkdir -p a/a1/assets/a1-1 a/a1/assets/a1-2 a/a2 b/b1/b1-2/b1-2-3/assets c
touch a/a1/assets/a1-1/a1-1.js a/a1/assets/a1-2/a1-2.js a/a2/a2.js b/b1/b1-2/b1-2-3/assets/b1-2-3.js b/b.js c/c.js
touch c/assets.js
劇本:
#!/bin/bash
shopt -s globstar # enable ** to recurse all the directories
files=() # create array variable
for f in **/*.js; do # glob pattern match all .js files
if [[ ! "$f" =~ "assets/" ]]; then # regex match all paths that do NOT contain an 'assets' directory
files+=("$f") # add it to the files array
fi
done
printf %s\\n "${files[@]}" # print the files array
結果:
a/a2/a2.js
b/b.js
c/assets.js
c/c.js
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.