Bash

測試目錄中是否存在任何與特定模式不匹配的文件

  • May 24, 2019

我對此有很大的困難。我正在嘗試測試目錄中是否存在與給定模式不匹配的文件,返回真或假。

在這種情況下,其中的文件$dir不以下劃線開頭,_. 我想我會嘗試if [ -f $dir/!(_*) ]if [ $dir -f -name ! _* ]

或者 if ls $dir/!(_*) 1> /dev/null 2>&1

但它總是會說Too many argumentssyntax 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

這種方法還可以檢測到名稱不以下劃線開頭的正常文件的符號連結。

循環對於轉移我們可能匹配的非正常文件(例如目錄名稱)的任何文件名是必要的。

zshshell 中,您可以使用"$dir"/[^_]*(.)保證只匹配正常文件的模式(如果它匹配任何內容)。


對於更複雜的模式,您可以天真地將匹配的項目數與匹配的項目數進行比較*。如果它們不同,則有些名稱與復雜模式不匹配。

在中,您可以在啟用shell 選項後bash使用擴展的 globbing 模式。一般形式是。您仍然需要檢查上述擴展的結果,以查看它是否擴展為任何內容。!(PATTERN)``extglob``shopt -s extglob``!(pattern1|pattern2|pattern3|etc)

名稱不以下劃線開頭的範例可能會使用!(_*)擴展的萬用字元模式,但請注意,!(_)*這不起作用,因為它會匹配每個可見的名稱,就像*會一樣。

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