Muh*_*uhd 63 command-line find
如何获取包含名称与特定模式匹配的文件的子目录列表?
更具体地说,我正在寻找包含文件名中出现字母“f”的文件的目录。
理想情况下,该列表不会有重复项,并且只包含没有文件名的路径。
Joh*_*024 61
find . -type f -name '*f*' | sed -r 's|/[^/]+$||' |sort |uniq
Run Code Online (Sandbox Code Playgroud)
以上查找当前目录 ( .)下的所有文件,这些文件是常规文件 ( -type f) 并f在其名称中的某处 ( -name '*f*')。接下来,sed删除文件名,只留下目录名。然后,对目录列表进行排序 ( sort) 并删除重复项 ( uniq)。
该sed命令由一个替代品组成。它查找与正则表达式的/[^/]+$匹配项,并用空替换任何匹配项。美元符号表示该行的结尾。 [^/]+'表示一个或多个不是斜杠的字符。因此,/[^/]+$表示从最后一个斜杠到行尾的所有字符。换句话说,这与完整路径末尾的文件名匹配。因此, sed 命令删除文件名,保持文件所在目录的名称不变。
许多现代sort命令都支持一个不必要的-u标志uniq。对于 GNU sed:
find . -type f -name '*f*' | sed -r 's|/[^/]+$||' |sort -u
Run Code Online (Sandbox Code Playgroud)
而且,对于 MacOS sed:
find . -type f -name '*f*' | sed -E 's|/[^/]+$||' |sort -u
Run Code Online (Sandbox Code Playgroud)
此外,如果您的find命令支持它,则可以find直接打印目录名称。这避免了需要sed:
find . -type f -name '*f*' -printf '%h\n' | sort -u
Run Code Online (Sandbox Code Playgroud)
上述版本会被包含换行符的文件名混淆。一个更健壮的解决方案是对以 NUL 结尾的字符串进行排序:
find . -type f -name '*f*' -printf '%h\0' | sort -zu | sed -z 's/$/\n/'
Run Code Online (Sandbox Code Playgroud)
Pat*_*lor 34
为什么不试试这个:
find / -name '*f*' -printf "%h\n" | sort -u
Run Code Online (Sandbox Code Playgroud)
基本上有两种方法可以用来做到这一点。一个将解析字符串,而另一个将操作每个文件。使用诸如grep, 之类的工具解析字符串sed,或者awk显然会更快,但这里有一个示例显示了两者,以及如何“分析”这两种方法。
对于下面的示例,我们将使用以下数据
$ touch dir{1..3}/dir{100..112}/file{1..5}
$ touch dir{1..3}/dir{100..112}/nile{1..5}
$ touch dir{1..3}/dir{100..112}/knife{1..5}
Run Code Online (Sandbox Code Playgroud)
*f*从dir1/*以下位置删除一些文件:
$ rm dir1/dir10{0..2}/*f*
Run Code Online (Sandbox Code Playgroud)
在这里,我们将使用以下工具find、grep、 和sort。
$ find . -type f -name '*f*' | grep -o "\(.*\)/" | sort -u | head -5
./dir1/dir103/
./dir1/dir104/
./dir1/dir105/
./dir1/dir106/
./dir1/dir107/
Run Code Online (Sandbox Code Playgroud)
与以前相同的工具链,除了这次我们将使用dirname代替grep。
$ find . -type f -name '*f*' -exec dirname {} \; | sort -u | head -5
./dir1/dir103
./dir1/dir104
./dir1/dir105
./dir1/dir106
./dir1/dir107
Run Code Online (Sandbox Code Playgroud)
注意:以上示例head -5仅用于限制我们为这些示例处理的输出量。他们通常会被删除以获得您的完整列表!
我们可以使用time来看看这两种方法。
目录名
real 0m0.372s
user 0m0.028s
sys 0m0.106s
Run Code Online (Sandbox Code Playgroud)
格雷普
real 0m0.012s
user 0m0.009s
sys 0m0.007s
Run Code Online (Sandbox Code Playgroud)
因此,如果可能,最好处理字符串。
grep & PCRE
$ find . -type f -name '*f*' | grep -oP '^.*(?=/)' | sort -u
Run Code Online (Sandbox Code Playgroud)
sed
$ find . -type f -name '*f*' | sed 's#/[^/]*$##' | sort -u
Run Code Online (Sandbox Code Playgroud)
awk
$ find . -type f -name '*f*' | awk -F'/[^/]*$' '{print $1}' | sort -u
Run Code Online (Sandbox Code Playgroud)