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


在GNU中,你可以使用-printf参数,例如:

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

如果您正在使用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

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

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

我已经找到了一个解决方案(在makandracards页面),这给了最新的文件名:

ls -1tr * | tail -1

(感谢Arne Hartherz)

我用它来写cp:

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

如果您只想对文件名运行一些操作,那么使用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

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

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

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

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

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

-execdir utility[参数…]]; -execdir primary与-exec primary相同,不同之处在于实用程序将从包含当前文件的目录执行。

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


在mac (BSD查找)上使用:

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

-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会发送所有的路径参数(实际上是5000个)而不带-n1。不适用于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

老实说,basename和dirname解决方案更简单,但你也可以看看这个:

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

or

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

or

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

正如其他人指出的那样,您可以将find和basename结合起来,但是默认情况下basename程序一次只在一个路径上操作,因此可执行文件必须为每个路径启动一次(使用find…-exec或find…| xargs -n 1),可能会很慢。

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

例子:

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

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

下面是xargs basename -a和xargs -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实际上要快得多。