如何使用find命令列出文件名而不列出路径?

如何使用find命令列出文件名而不列出路径?

我已经在线检查了一些答案,但是当命令中有参数时它们不起作用-name(也许我做错了什么,不确定)。我想做的是仅列出文件名(而不是目录/路径),更复杂的是,我有相同的文件名但具有不同的扩展名,所以我需要使用-name和来过滤结果-o,问题是我的建议看到使用 或-printfbasename当有 时,这些效果不佳-name *.txt -o name *.pdf。还有其他方法可以解决这个问题吗?

我的文件示例:

/dir1/dir2/dir3/dir4/
                    /file1.txt
                    /file1.pdf
                    /file1.ods ...etc.

我只对每个列表列出一种或多种类型的文件感兴趣(通过使用-name来过滤我的结果。

是否可以仅使用 1 个find命令来完成它,或者我必须分两步完成(将结果保存在临时文件中,然后从临时文件中过滤/删除目录)?我试图完成的结果是一个文本文件,每行都有文件名:

file1.txt
file1.pdf
file1.ods
file2.txt
file2.pdf
etc.

我使用的命令是

find /dir1/dir2/dir3/dir4/ -type f -name '*.txt' -o -name '*.pdf' -o -name '*.ods' -printf "%f\n"

我正在使用 GNU 查找。

更新

原来我必须把\(...\),正如αГsнιη提醒的那样

答案1

当以逻辑 OR 模式使用多个表达式时,-o您需要将它们全部括在 内\( ... \),否则始终尊重最后一个表达式结果;并-printf '%f\n'用于仅打印删除了所有前导目录的文件名。

find . -type f \( -name '*.pdf' -o -name '*.txt' \) -printf '%f\n'

man find在下面运营商关于以下部分( expr )

运营商
...

(expr)
强制优先。由于括号对于 shell 来说是特殊的,因此通常需要用引号引起来。

因此您可以使用\( ... \)or '(' ... ')'(括号前后的空格很重要)来转义它们。

答案2

正如已经提到的,您需要将-name测试分组在括号中。这些括号需要转义\( ... \)或引用为例如,'(' ... ')'以保护它们免受 shell 的影响(否则它们将指定子 shell)。

使用 standard find,并且还使处理文件名后缀稍微容易一些:

set -- txt pdf ods

for suffix do
    set -- "$@" -o -name "*.$suffix"
    shift
done
shift

find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename {} \;

首先将位置参数设置为我们想要查看的文件名后缀列表(如果这是一个脚本,也可以从命令行获取),并构造-name测试的 OR 列表。然后在命令行中使用它find

然后,命令find本身basename为每个找到的名称调用该实用程序。

作为替代方案,我们可以使用参数替换来删除每个路径名中除文件名部分之外的所有内容,但为此我们必须将路径名传递给内联sh -c脚本:

# [...] as before [...]

find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec sh -c '
    for pathname do
        printf "%s\n" "${pathname##*/}"
    done' sh {} +

我希望它比使用的变体运行得更快basename,至少如果有很多文件名需要处理,尽管使用basenamecoreutils 的 GNU,你可以使用-a--multiple喜欢这样:

find /dir1/dir2/dir3/dir4 \( "$@" \) -type f -exec basename -a {} +

这会调用basename尽可能少的次数。但话又说回来,如果您安装了 coreutils,您也可能会使用 GNU 来安装 findutils find,并且可以用来-printf '%f\n'做同样的事情。

相关内容