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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5456120/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 00:34:44  来源:igfitidea点击:

How to only get file name with Linux 'find'?

linuxshellfind

提问by marverix

I'm using find to all files in directory, so I get a list of paths. However, I need only file names. i.e. I get ./dir1/dir2/file.txtand I want to get file.txt

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

采纳答案by SiegeX

In GNU findyou can use -printfparameter for that, e.g.:

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

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

回答by kurumi

If you are using GNU find

如果您使用 GNU 查找

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

Or you can use a programming language such as Ruby(1.9+)

或者您可以使用诸如 Ruby(1.9+) 之类的编程语言

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

If you fancy a bash (at least 4) solution

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

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

回答by Kambus

If your find doesn't have a -printf option you can also use basename:

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

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

回答by jazzinka

I've found a solution (on makandracards page), that gives just the newest file name:

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

ls -1tr * | tail -1

(thanks goes to Arne Hartherz)

(感谢 Arne Hartherz)

I used it for cp:

我用它cp

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

回答by j03m

If you want to run some action against the filename only, using basenamecan be tough.

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

For example this:

例如这个:

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

will just echo basename /my/found/path. Not what we want if we want to execute on the filename.

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

But you can then xargsthe output. for example to kill the files in a dir based on names in another dir:

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

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

回答by kenorb

Use -execdirwhich automatically holds the current file in {}, for example:

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

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

You can also use $PWDinstead of .(on some systems it won't produce an extra dot in the front).

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

If you still got an extra dot, alternatively you can run:

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

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


-execdir utility [argument ...] ;

The -execdirprimary is identical to the -execprimary with the exception that utility will be executed from the directory that holds the current file.

-execdir utility [argument ...] ;

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

When used +instead of ;, then {}is replaced with as many pathnames as possible for each invocation of utility. In other words, it'll print all filenames in one line.

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

回答by spectrum

On mac (BSD find) use:

在 mac (BSD find) 上使用:

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

回答by minusf

-execand -execdirare slow, xargsis king.

-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's parallelism also helps.

xargs的并行性也有帮助。

Funnily enough i cannot explain the last case of xargswithout -n1. It gives the correct result and it's the fastest ˉ\_(ツ)_/ˉ

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

(basenametakes only 1 path argument but xargswill send them all (actually 5000) without -n1. does not work on linux and openbsd, only macOS...)

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

Some bigger numbers from a linux system to see how -execdirhelps, but still much slower than a parallel xargs:

来自 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

回答by Freeman

Honestly basenameand dirnamesolutions are easier, but you can also check this out :

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

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

or

或者

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

or

或者

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

回答by alaniwi

As others have pointed out, you can combine findand basename, but by default the basenameprogram will only operate on one path at a time, so the executable will have to be launched once for each path (using either find ... -execor find ... | xargs -n 1), which may potentially be slow.

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

If you use the -aoption on basename, then it can accept multiple filenames in a single invocation, which means that you can then use xargswithout the -n 1, to group the paths together into a far smaller number of invocations of basename, which should be more efficient.

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

Example:

例子:

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

Here I've included the -print0and -0(which should be used together), in order to cope with any whitespace inside the names of files and directories.

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

Here is a timing comparison, between the xargs basename -aand xargs -n1 basenameversions. (For sake of a like-with-like comparison, the timings reported here are after an initial dummy run, so that they are both done after the file metadata has already been copied to I/O cache.) I have piped the output to cksumin both cases, just to demonstrate that the output is independent of the method used.

这是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

As you can see, it really is substantially faster to avoid launching basenameevery time.

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