如何仅使用 Linux 'find' 获取文件名?

Posted

技术标签:

【中文标题】如何仅使用 Linux \'find\' 获取文件名?【英文标题】:How to only get file name with Linux 'find'?如何仅使用 Linux 'find' 获取文件名? 【发布时间】:2011-07-24 06:57:00 【问题描述】:

我正在使用查找目录中的所有文件,所以我得到了一个路径列表。但是,我只需要文件名。即我得到./dir1/dir2/file.txt,我想得到file.txt

【问题讨论】:

【参考方案1】:

在 GNU find 中,您可以为此使用 -printf 参数,例如:

find /dir1 -type f -printf "%f\n"

【讨论】:

显然是答案,但缺乏细节。 当我使用多种文件类型(-o 开关)时,这对我不起作用 找到:-printf: 未知的主要或操作员 @Urchin 只要您有正确的逻辑,就没有理由不应该这样做(即-o 的优先级低于隐含的-a,因此您经常需要对-o 参数进行分组) find ./ -name "*" -printf "%f\n" | xargs grep "searchName" 这不起作用,它只会打印:about.php:没有这样的文件或目录 grep:site-themes.php:没有这样的文件或目录或find ./ -name "*" | xargs grep "searchName" -printf "%f\n" 仍然错误【参考方案2】:

如果你的 find 没有 -printf 选项,你也可以使用 basename:

find ./dir1 -type f -exec basename  \;

【讨论】:

引用分号是另一种消除歧义的方法:... ';'【参考方案3】:

如果您使用的是 GNU 查找

find . -type f -printf "%f\n"

或者您可以使用 Ruby(1.9+) 等编程语言

$ ruby -e 'Dir["**/*"].each|x| puts File.basename(x)'

如果您喜欢 bash(至少 4 个)解决方案

shopt -s globstar
for file in **; do echo $file##*/; done

【讨论】:

我受到您对帮助 sleske 的回答的启发:serverfault.com/a/745968/329412【参考方案4】:

使用-execdir自动将当前文件保存在中,例如:

find . -type f -execdir echo '' ';'

您也可以使用$PWD 代替.(在某些系统上它不会在前面产生一个额外的点)。

如果你还有一个额外的点,或者你可以运行:

find . -type f -execdir basename '' ';'

-execdir utility [argument ...] ;

-execdir 主数据库与-exec 主数据库相同,只是将从保存当前文件的目录执行实用程序。

当使用+ 而不是; 时, 被替换为每次调用实用程序时尽可能多的路径名。换句话说,它将在一行中打印所有文件名。

【讨论】:

我收到的是 ./filename 而不是 filename。根据您的需要,它可能会也可能不会好。 @user276648 尝试使用$PWD 而不是.【参考方案5】:

如果您只想对文件名执行一些操作,使用 basename 可能会很困难。

例如:

find ~/clang+llvm-3.3/bin/ -type f -exec echo basename  \; 

只会回显基本名称/my/found/path。如果我们想在文件名上执行,这不是我们想要的。

但是你可以然后xargs 输出。例如根据另一个目录中的名称杀死一个目录中的文件:

cd dirIwantToRMin;
find ~/clang+llvm-3.3/bin/ -type f -exec basename  \; | xargs rm

【讨论】:

不要回显 - find ~/clang+llvm-3.3/bin/ -type f -exec basename \; 【参考方案6】:

在 mac (BSD find) 上使用:

find /dir1 -type f -exec basename  \;

【讨论】:

【参考方案7】:

正如其他人指出的那样,您可以组合 findbasename,但默认情况下 basename 程序一次只能在一个路径上运行,因此必须为每个路径启动一次可执行文件(使用find ... -execfind ... | xargs -n 1),这可能会很慢。

如果您在basename 上使用-a 选项,那么它可以在一次调用中接受多个文件名,这意味着您可以在没有-n 1 的情况下使用xargs,将路径组合成一个basename 的调用次数要少得多,这应该更有效。

例子:

find /dir1 -type f -print0 | xargs -0 basename -a

这里我包含了-print0-0(应该一起使用),以处理文件和目录名称中的任何空格。

这是xargs basename -axargs -n1 basename 版本之间的时间比较。 (为了进行类似比较,这里报告的时间是在初始虚拟运行之后,因此它们都是在文件元数据已经复制到 I/O 缓存之后完成的。)我已将输出通过管道传输到cksum 在这两种情况下,只是为了证明输出与使用的方法无关。

$ time sh -c 'find /usr/lib -type f -print0 | xargs -0 basename -a | cksum'
2532163462 546663

real    0m0.063s
user    0m0.058s
sys 0m0.040s

$ time sh -c 'find /usr/lib -type f -print0 | xargs -0 -n 1 basename | cksum' 
2532163462 546663

real    0m14.504s
user    0m12.474s
sys 0m3.109s

如您所见,避免每次都启动basename 确实要快得多。

【讨论】:

更彻底地阅读@minusf 的答案后,我发现在Mac 上basename 将接受多个文件名,而无需任何额外的命令行参数。这里使用-a 是在Linux 上。 (basename --version 告诉我basename (GNU coreutils) 8.28。)【参考方案8】:

-exec-execdir 很慢,xargs 为王。

$ alias f='time find /Applications -name "*.app" -type d -maxdepth 5'; \
f -exec basename  \; | wc -l; \
f -execdir echo  \; | wc -l; \
f -print0 | xargs -0 -n1 basename | wc -l; \
f -print0 | xargs -0 -n1 -P 8 basename | wc -l; \
f -print0 | xargs -0 basename | wc -l

     139
    0m01.17s real     0m00.20s user     0m00.93s system
     139
    0m01.16s real     0m00.20s user     0m00.92s system
     139
    0m01.05s real     0m00.17s user     0m00.85s system
     139
    0m00.93s real     0m00.17s user     0m00.85s system
     139
    0m00.88s real     0m00.12s user     0m00.75s system

xargs 的并行性也有帮助。

有趣的是,如果没有-n1,我无法解释xargs 的最后一种情况。 它给出了正确的结果并且是最快的¯\_(ツ)_/¯

basename 只接受 1 个路径参数,但 xargs 将在没有 -n1 的情况下将它们全部发送(实际上是 5000 个)。不适用于 linux 和 openbsd,仅适用于 macOS...)

来自 linux 系统的一些更大的数字,看看 -execdir 有何帮助,但仍然比并行的 xargs 慢得多:

$ alias f='time find /usr/ -maxdepth 5 -type d'
$ f -exec basename  \; | wc -l; \
f -execdir echo  \; | wc -l; \
f -print0 | xargs -0 -n1 basename | wc -l; \
f -print0 | xargs -0 -n1 -P 8 basename | wc -l

2358
    3.63s real     0.10s user     0.41s system
2358
    1.53s real     0.05s user     0.31s system
2358
    1.30s real     0.03s user     0.21s system
2358
    0.41s real     0.03s user     0.25s system

【讨论】:

再增加一个数据点:在 openbsd 上长时间运行 find 它是最快的 -execdir,因为创建新进程是一项相对昂贵的操作。【参考方案9】:

老实说,basenamedirname 解决方案更简单,但您也可以查看一下:

find . -type f | grep -oP "[^/]*$"

find . -type f | rev | cut -d '/' -f1 | rev

find . -type f | sed "s/.*\///"

【讨论】:

【参考方案10】:

我找到了一个解决方案(在 makandracards 页面上),它只提供了最新的文件名:

ls -1tr * | tail -1

(感谢 Arne Hartherz)

我把它用于cp

cp $(ls -1tr * | tail -1) /tmp/

【讨论】:

这根本不能回答问题。

以上是关于如何仅使用 Linux 'find' 获取文件名?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Linux 上使用 grep 仅显示文件名?

Linux 命令:如何仅“查找”文本文件?

如何使用 BeautifulSoup4 仅获取“href”? [复制]

Linux 上如何仅获取一级子目录的大小?

find命令使用及Linux任务调度

lua如何从全路径中获取文件名(linux、windows通用)