測試目錄中是否存在任何與特定模式不匹配的文件
我對此有很大的困難。我正在嘗試測試目錄中是否存在與給定模式不匹配的文件,返回真或假。
在這種情況下,其中的文件
$dir
不以下劃線開頭,_
. 我想我會嘗試if [ -f $dir/!(_*) ]
,if [ $dir -f -name ! _* ]
或者
if ls $dir/!(_*) 1> /dev/null 2>&1
但它總是會說
Too many arguments
或syntax error near unexpected token "("
names=( "$dir"/[!_]* ) if [ -e "${names[0]}" ]; then echo 'there are filenames that do not start with underscore' printf '%d of them\n' "${#names[@]}" fi
或者,對於
/bin/sh
(並且bash
就此而言):set -- "$dir"/[!_]* if [ -e "$1" ]; then echo 'there are filenames that do not start with underscore' printf '%d of them\n' "$#" fi
簡而言之,擴展適當的 globbing 模式並測試它是否匹配存在的東西。
該
[!_]
模式將匹配任何不是下劃線的字元。它類似於正則表達式[^_]
,但文件名通配模式使用!
而不是^
否定字元類。當模式不匹配時,預設情況下,它將保持未擴展,這就是為什麼我們使用
-e
測試來確保匹配列表中的第一件事存在。我們無法真正測試返回列表的長度,因為如果長度為 1,它可能仍然沒有匹配任何內容(除非您在 中nullglob
設置了 shell 選項bash
)。如果您想專門測試正常文件,這會變得有點棘手,因為通配模式匹配任何名稱(目錄、正常文件和所有其他類型的文件)。但這會做到:
names=( "$dir"/[!_]* ) while [ "${#names[@]}" -gt 0 ] && [ ! -f "${names[0]}" ]; do names=( "${names[@]:1}" ) done if [ -f "${names[0]}" ]; then echo 'there are at least one regular file here (or a symlink to one)' echo 'whose filename does not start with underscore' fi
或者,對於
/bin/sh
:set -- "$dir"/[!_]* while [ "$#" -gt 0 ] && [ ! -f "$1" ]; do shift done if [ -f "$1" ]; then echo 'there are at least one regular file here (or a symlink to one)' echo 'whose filename does not start with underscore' fi
這種方法還可以檢測到名稱不以下劃線開頭的正常文件的符號連結。
循環對於轉移我們可能匹配的非正常文件(例如目錄名稱)的任何文件名是必要的。
在
zsh
shell 中,您可以使用"$dir"/[^_]*(.)
保證只匹配正常文件的模式(如果它匹配任何內容)。對於更複雜的模式,您可以天真地將匹配的項目數與匹配的項目數進行比較
*
。如果它們不同,則有些名稱與復雜模式不匹配。在中,您可以在啟用shell 選項後
bash
使用擴展的 globbing 模式。一般形式是。您仍然需要檢查上述擴展的結果,以查看它是否擴展為任何內容。!(PATTERN)``extglob``shopt -s extglob``!(pattern1|pattern2|pattern3|etc)
名稱不以下劃線開頭的範例可能會使用
!(_*)
擴展的萬用字元模式,但請注意,!(_)*
這不起作用,因為它會匹配每個可見的名稱,就像*
會一樣。