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


266

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

Answers:


359

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

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

9
显然答案是,但是它缺少细节。
杰森·麦克莱里

25
这仅适用于GNU
Osama F Elias 2014年

3
当我使用多种文件类型(-o开关)时,这对我不起作用
Urchin

9
查找:-printf:未知的主操作符或运算符
holms,2014年

@Urchin没有理由只要您有正确的逻辑就不应该这样做(即-o,优先级比隐含的低-a,因此您经常希望对您的-o论点进行分组)
恢复莫妮卡,请2014年

157

如果发现没有-printf选项,则还可以使用basename:

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

17
引用分号是消除歧义的另一种方法:... {} ';'
davidchambers 2012年

28

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

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

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

如果仍然有多余的点,则可以运行:

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

-execdir utility [argument ...] ;

-execdir初级是相同的-exec初级不同之处在于实用程序将来自该目录被执行保持当前文件

如果使用+代替;,则{}每次实用程序调用都将被替换为尽可能多的路径名。换句话说,它将在一行中打印所有文件名。


我要./filename代替filename。根据您的需要,它可能会或可能不会很好。
user276648

@ user276648尝试使用$PWD代替.
kenorb

24

如果您使用的是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

您的帮助我对您的帮助感到鼓舞:serverfault.com/a/745968/329412
Nolwennig,2016年

11

如果只想对文件名运行某些操作,则使用起来basename可能很困难。

例如:

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

只会回显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 {} \;
commonpike

7

在Mac(BSD find)上,使用:

find /dir1 -type f -exec basename {} \;

1

-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的并行性也有帮助。

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

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

1
仅一个数据点:长期运行在openbsd上,find它是-execdir最快的,因为创建新进程是相对昂贵的操作。
minusf

1

老实说basenamedirname解决方案更容易,但是您也可以查看以下内容:

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

要么

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

要么

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

0

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

如果在上使用-a选项basename,则它可以在一次调用中接受多个文件名,这意味着您可以xargs不使用-n 1来将路径分组为更少的调用数量basename,这应该更有效率。

例:

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

在这里,我包括了-print0and -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上使用here。(basename --version告诉我basename (GNU coreutils) 8.28。)
阿拉尼维

-3

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

ls -1tr * | tail -1

(感谢Arne Hartherz)

我用它cp

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

2
这根本无法回答问题。
kenorb 2015年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.