【问题标题】:Linux Find Command Hide Base DirectoryLinux 查找命令隐藏基本目录
【发布时间】:2023-04-03 22:55:02
【问题描述】:

编者注:这个问题含糊不清,因为它把两个不相关的任务混为一谈:
(a) 使用-printf 操作打印 仅文件名(没有路径组件),并且
(b) 在-exec 操作的上下文中通过{}
传递单纯的文件名作为参数 (a) 被错误地视为实现 (b) 的一种方式。
这种混淆导致至少有一个答案集中在(a)上。

我正在尝试使用 find 命令列出某个路径中的所有目录,但在输出中隐藏该路径。 -printf "%P\n" 标志应该隐藏 /path/to/directory/,但它不起作用:

find /path/to/directory/* -maxdepth 0 -type d -printf "%P\n" -exec sudo tar -zcpvf {}.tar.gz {} \;

例如,上述命令将使用以下命令创建档案:

/path/to/directory/dir1
/path/to/directory/dir2
/path/to/directory/dir3

我怎样才能修改我的命令来输出这个:

dir1
dir2
dir3

请注意:我知道我可以通过 cd /path/to/directory/ 然后使用 find 命令执行上述操作,但重要的是我避免使用 cd 并使用单个 find 命令完成所有操作。

【问题讨论】:

标签: linux shell find


【解决方案1】:
find  /path/to/directory/* -maxdepth 0 -type d -exec basename {} \;

找到所有目录find /path/to/directory/* -maxdepth 0 -type d

-exec basename {} \; - 使用 find 的结果参数执行 basename 命令

【讨论】:

  • 虽然这段代码 sn-p 可以解决问题,including an explanation 确实有助于提高您的帖子质量。请记住,您是在为将来的读者回答问题,而这些人可能不知道您提出代码建议的原因。
  • 这个建议根本没有解决任何问题,因为它完全忽略了我的 -exec 标志选项。
  • 这似乎工作了一会儿,然后“无法统计:没有这样的文件或目录。”也许 xargs 不适用于太多文件?
  • 这个答案正确地显示了如何打印文件名(这是OP要求的一个 - 尽管错误地试图解决一个不同的问题)。但是,使用 GNU find(在 Linux 上可以找到)的更简单、更有效的解决方案是 find /path/to/directory/* -maxdepth 0 -type d -printf '%f\n'。使用 -exec 并假设 GNU 或 BSD/OSX basename,更有效的解决方案是 find /path/to/directory/* -maxdepth 0 -type d -exec basename -a {} +。从好的方面来说,这个答案中的命令是 POSIX 兼容的。
【解决方案2】:

由于您只处理 child 目录(直接子目录),shell 循环可能是更简单的解决方案:

(cd "/path/to/dir" && for d in */; do sudo tar -zcpvf "${d%/}".tar.gz "$d"; done)

我知道你想避免cd,但是通过将整个命令包含在(…) 中,它在subshel​​l 中运行,因此当前shell 的工作目录。保持不变。

本答案的其余部分讨论如何使用 GNU find 解决问题。

-execdir 解决方案也可以与 BSD/OSX find 一起使用,而且实际上会更简单。


至于获取find-printf 打印 文件名,没有任何目录组件:使用@987654329 @格式说明符:

find /path/to/dir/* -maxdepth 0 -type d -printf "%f\n"

这将打印指定目录中所有立即子目录的名称。

但是,打印的内容对使用-exec 操作时{} 展开的内容没有影响{} 始终展开为路径匹配,它总是包含指定为输入的路径组件。

但是,-execdir 操作可能会给你想要的东西

  • 在执行指定命令之前切换到手头的目录

  • 它将{} 扩展为./<filename> - 即,以./ 为前缀的纯文件名(在本例中为目录名) - 并将其传递给指定的命令。

    李>

因此:

find /path/to/dir -mindepth 1 -maxdepth 1 -type d -execdir sudo tar -zcpvf {}.tar.gz {} \;

警告-execdir 的行为仅与输入路径的后代文件的描述相同;对于输入路径本身,奇怪的是,{} 仍然扩展为输入路径原样[1] .

因此,上面的命令-maxdepth 0 使用通配符(/path/to/dir/*),而是使用/path/to/dir 并让find 枚举包含的项目,这些项目比在级别 1 - 因此-maxdepth 1;由于输入路径本身不应包含在内,因此必须添加-mindepth 1

请注意,行为会略有不同:find always 在枚举中包含 hidden 项,而默认情况下,shell 的通配符 (*) 包含 不是。


如果应该去除 {} 扩展中的 ./ 前缀,还需要做更多工作:

find /path/to/dir -mindepth 1 -maxdepth 1 -type d \
  -execdir sh -c 'd=${1##*/}; sudo tar -zcpvf "$d".tar.gz "$d"' - {} \;

涉及 shell (sh) 允许使用 shell 参数扩展去除 ./ 前缀(${1##*/} 实际上会去除 any 路径组件)。 注意虚拟参数-,shell 分配给$0,我们在这里不感兴趣; {} 然后变成shell 参数$1


[1] 如果输入路径本身是相对的,则带有 ./ 前缀;请注意,BSD/OSX find 没有表现出这种怪癖:它总是将{} 扩展为仅文件名,没有任何路径组件。

【讨论】:

  • 这几乎有效!除了它在前面放了一个丑陋的空白目录,例如:./dir/filename.txt。有什么办法可以删除 ./ 所以输出只是 dir/filename.txt?
  • 是的,tar 工作正常,但我的存档中没有 dir1 dir2 我得到的是 ./dir1 ./dir2。
  • find:路径必须在表达式之前:-execdir 用法:find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt |exec] [路径...] [表达式]
  • @GTSJoe:听起来像是错字; -exec 之后的某处你有一个 unquoted / - 也许你忘记了 shell 命令周围的单引号?
猜你喜欢
  • 1970-01-01
  • 2023-03-24
  • 1970-01-01
  • 2012-09-13
  • 1970-01-01
  • 2013-12-14
  • 2021-08-26
  • 2015-06-30
  • 2013-02-05
相关资源
最近更新 更多