编者按:这个问题不明确,因为它将两个无关的任务混为一谈:(a)使用-printf操作仅打印文件名(无路径组件),以及(b)在通过{}采取-exec行动的情况下,仅以文件名作为论据。(a)被错误地认为是实施(b)的一种方式。这种混淆导致至少有一个答案集中在(a)。
我试图使用find命令列出某个路径中的所有目录,但在输出中隐藏该路径。-printf"%p"标志应该隐藏/path/to/directory/,但不起作用:
1 2
| find /path/to/directory/* -maxdepth 0 -type d -printf"%P
" -exec sudo tar -zcpvf {}.tar.gz {} \; |
例如,上面的命令将使用以下内容创建存档:
1 2 3
| /path/to/directory/dir1
/path/to/directory/dir2
/path/to/directory/dir3 |
如何修改命令以输出:
请注意:我知道我可以通过cd/path/to/directory/然后使用find命令来完成上述操作,但重要的是避免使用cd,并使用单个find命令来完成所有操作。
- 如果答案解决了您的问题,请单击大复选标记(?)接受它。紧挨着它。如果你发现其他答案有帮助,请向上投票。接受和支持投票有助于未来的读者。请参阅相关的帮助中心文章。如果您的问题尚未完全回答,请提供反馈。
- 请看看当有人回答我的问题时我该怎么做?
1
| find /path/to/directory/* -maxdepth 0 -type d -exec basename {} \; |
查找所有目录find /path/to/directory/* -maxdepth 0 -type d。
-exec basename {} \;—使用find中的结果参数执行basename命令
- 虽然这个代码片段可以解决这个问题,但包含一个解释确实有助于提高文章的质量。请记住,您将来会为读者回答这个问题,而这些人可能不知道您的代码建议的原因。
- 这个建议根本不能解决任何问题,因为它完全忽略了我的-exec标志选项。
- 这似乎工作了一段时间,然后"cannot stat:no such file or directory."也许xargs不能处理太多的文件?
- 这个答案正确地显示了如何只打印文件名(这是OP要求的内容之一——尽管在错误地尝试解决另一个问题时)。但是,使用GNU find(在Linux上找到)的更简单、更高效的解决方案是find /path/to/directory/* -maxdepth 0 -type d -printf '%f
'。使用-exec,假设GNU或BSD/OSX basename,一个更有效的解决方案是find /path/to/directory/* -maxdepth 0 -type d -exec basename -a {} +。在正方面,这个答案中的命令是符合POSIX的。
因为您只处理子目录(直接子目录),所以shell循环可能是更简单的解决方案:
1
| (cd"/path/to/dir" && for d in */; do sudo tar -zcpvf"${d%/}".tar.gz"$d"; done) |
我知道你想避开cd,但是通过将整个命令封闭在(…)中,它在一个子shell中运行,所以当前shell的工作目录。保持不变。
这个答案的其余部分讨论了如何使用gnu find来解决这个问题。
-execdir解决方案也可以与BSD/OSXfind一起使用,实际上在那里会更简单。
至于让find的-printf只打印文件名,不带任何目录组件:使用%f格式说明符:
1 2
| find /path/to/dir/* -maxdepth 0 -type d -printf"%f
" |
这将只打印指定目录中所有直接子目录的名称。
但是,您打印的内容对使用-exec操作时{}扩展到的内容没有影响:{}始终扩展到匹配的路径,该路径始终包含指定为输入的路径组件。
但是,-execdir行动可能给你想要的:
因此:
1
| find /path/to/dir -mindepth 1 -maxdepth 1 -type d -execdir sudo tar -zcpvf {}.tar.gz {} \; |
警告:-execdir只对作为输入路径后代的文件进行描述;奇怪的是,对于输入路径本身,{}仍然按原样扩展到输入路径[1].
因此,上面的命令不将globbing(/path/to/dir/*与-maxdepth 0一起使用,而是使用/path/to/dir并让find进行包含项的枚举,这些包含项比在级别1上要多,因此-maxdepth 1;由于不应包括输入路径本身,因此必须添加-mindepth 1。
注意,这样的行为就有了细微的不同:find总是在枚举中包含隐藏项,而shell的globbing(*)在默认情况下则没有。
如果需要去掉{}扩展中的./前缀,则需要做更多的工作:
1 2
| 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##*/}实际上会除去任何路径组件)来除去./前缀。注意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][path…][expression]
- @GTSjoe:听起来像是拼写错误;在-exec之后的某个地方,你有一个未加引号的/——也许你忘记了shell命令的单引号?