如何仅使用 Linux‘find’获取文件名?
- 2024-10-21 09:14:00
- admin 原创
- 89
问题描述:
我正在使用 find 查找目录中的所有文件,因此我得到了一个路径列表。但是,我只需要文件名。即我得到了./dir1/dir2/file.txt
并且我想要得到file.txt
解决方案 1:
在 GNU 中find
你可以使用-printf
参数来实现这一点,例如:
find /dir1 -type f -printf "%f
"
解决方案 2:
如果你的 find 没有 -printf 选项,你也可以使用 basename:
find ./dir1 -type f -exec basename {} ;
解决方案 3:
使用-execdir
它会自动保存当前文件{}
,例如:
find . -type f -execdir echo '{}' ';'
您也可以使用它$PWD
来代替.
(在某些系统上它不会在前面产生额外的点)。
如果您还有一个多余的点,您也可以运行:
find . -type f -execdir basename '{}' ';'
-execdir utility [argument ...] ;
主要程序
-execdir
与主要程序相同,不同之处在于实用程序将从保存当前文件-exec
的目录执行。
当使用+
代替 时;
,{}
每次调用实用程序时都会用尽可能多的路径名替换。换句话说,它会在一行中打印所有文件名。
解决方案 4:
如果你使用 GNU find
find . -type f -printf "%f
"
或者你可以使用 Ruby(1.9+)等编程语言
$ ruby -e 'Dir["**/*"].each{|x| puts File.basename(x)}'
如果你喜欢 bash (至少 4) 解决方案
shopt -s globstar
for file in **; do echo ${file##*/}; done
解决方案 5:
如果您只想对文件名运行某些操作,使用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
解决方案 6:
正如其他人指出的那样,您可以组合find
和basename
,但默认情况下basename
程序一次只能在一条路径上运行,因此必须为每个路径启动一次可执行文件(使用或find ... -exec
)find ... | xargs -n 1
,这可能会很慢。
如果您使用-a
选项basename
,那么它可以在一次调用中接受多个文件名,这意味着您可以在xargs
不使用的情况下使用-n 1
,将路径组合在一起,形成更少数量的调用basename
,这应该更有效率。
例子:
find /dir1 -type f -print0 | xargs -0 basename -a
这里我包含了-print0
and -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
每次启动确实要快得多。
解决方案 7:
在 Mac(BSD find
)上使用:
find /dir1 -type f -exec basename {} ;
解决方案 8:
老实说basename
,dirname
解决方案更简单,但你也可以看看这个:
find . -type f | grep -oP "[^/]*$"
或者
find . -type f | rev | cut -d '/' -f1 | rev
或者
find . -type f | sed "s/.*///"
解决方案 9:
-exec
且慢-execdir
,xargs
为王。
$ alias f='time find /Applications -name "*.app" -type d -maxdepth 5'; \nf -exec basename {} ; | wc -l; \nf -execdir echo {} ; | wc -l; \nf -print0 | xargs -0 -n1 basename | wc -l; \nf -print0 | xargs -0 -n1 -P 8 basename | wc -l; \nf -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; \nf -execdir echo {} ; | wc -l; \nf -print0 | xargs -0 -n1 basename | wc -l; \nf -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
解决方案 10:
我找到了一个解决方案(在 makandracards 页面上),它只提供最新的文件名:
ls -1tr * | tail -1
(感谢 Arne Hartherz)
我使用它来cp
:
cp $(ls -1tr * | tail -1) /tmp/
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件