我正在使用find命令查找目录中的所有文件,以获取路径列表。但是,我只需要文件名,例如,我得到了./dir1/dir2/file.txt
,我想要得到file.txt
find
中,你可以使用-printf
参数来实现这一点,例如:find /dir1 -type f -printf "%f\n"
如果你的find命令没有-printf选项,你也可以使用basename:
find ./dir1 -type f -exec basename {} \;
... {} ';'
- davidchambersexec
调用与上面的 printf
解决方案相比会产生显著的性能开销。 - ABC Taylor使用-execdir
,它会自动将当前文件保存在{}
中,例如:
find . -type f -execdir echo '{}' ';'
在某些系统中,您还可以使用$PWD
代替.
(这样不会在前面产生多余的点)。
如果您仍然得到了额外的点,则可以尝试运行以下命令:
find . -type f -execdir basename '{}' ';'
-execdir utility [argument ...] ;
-execdir
命令与-exec
命令十分相似,但是命令 utility 会在包含当前文件的目录下执行。
如果使用 +
替代 ;
,那么对于每次调用 utility,{}
将被尽可能多的路径名替换。换句话说,它将在一行中打印所有文件名。
./filename
而不是 filename
。根据您的需求,这可能是可以接受的,也可能不行。 - user276648$PWD
替代 .
。 - kenorb如果您正在使用GNU find命令
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
如果您只想对文件名执行某些操作,使用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在Mac上(BSD find
),请使用以下命令:
find /dir1 -type f -exec 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
确实可以显著提高速度。
basename
将接受多个文件名而不需要任何额外的命令行参数。这里使用的是Linux中的-a
。(basename --version
告诉我basename (GNU coreutils) 8.28
。) - alani说实话,basename
和dirname
的解决方案更简单易懂,但你也可以尝试以下方法:
find . -type f | grep -oP "[^/]*$"
或者
find . -type f | rev | cut -d '/' -f1 | rev
或者
find . -type f | sed "s/.*\///"
-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
只需要一个路径参数,但是如果没有 -n1
,xargs
将发送所有路径参数(实际上是 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
find
中,-execdir
成为最快的选项,因为创建新进程是一项相对昂贵的操作。 - minusf我找到了一个解决方案(在makandracards页面上),它只提供最新的文件名:
ls -1tr * | tail -1
感谢Arne Hartherz的贡献
我在使用cp
时用到了它:
cp $(ls -1tr * | tail -1) /tmp/
find ./ -name "*" | xargs grep "searchName" -printf "%f\n"
仍然会出现错误。 - Gankfind -printf "%f\n" -exec echo {} \;
显示原始文件名被传递了下去。 - Alex Riina