![对匹配位置(而不是原始位置)文件夹的文件递归执行命令](https://linux22.com/image/212424/%E5%AF%B9%E5%8C%B9%E9%85%8D%E4%BD%8D%E7%BD%AE%EF%BC%88%E8%80%8C%E4%B8%8D%E6%98%AF%E5%8E%9F%E5%A7%8B%E4%BD%8D%E7%BD%AE%EF%BC%89%E6%96%87%E4%BB%B6%E5%A4%B9%E7%9A%84%E6%96%87%E4%BB%B6%E9%80%92%E5%BD%92%E6%89%A7%E8%A1%8C%E5%91%BD%E4%BB%A4.png)
我想递归地将文件从文件夹中转换.docx
为.doc
文件夹中的文件。问题是所有输出文件都是在我运行以下命令的文件夹中创建的,而不是在源文件的位置中创建的:
find -type f -name "*.docx"-exec libreoffice --convert-to doc {} \;
我知道 find 为libreoffice
命令提供了源文件,并且输出显然必须位于当前位置,所以我如何使用命令递归地循环到文件夹中并从找到文件的位置执行命令,而不是最初的一个?
答案1
-execdir
如果您find
支持的话,这就是目的。 Linux 系统上默认的 GNUfind
确实有它。从man find
:
-execdir命令;
-execdir 命令 {} +
与 -exec 类似,但指定的命令是从包含匹配文件的子目录运行的,该子目录通常不是您开始查找的目录。 [。 。 。 ]
所以你要:
find . -type f -name "*.docx" -execdir libreoffice --convert-to doc {} \;
文件名将被插入到 的每个实例中{}
。如果-exec
使用,{}
将包括以 开头的相对路径./
。如果-execdir
使用,{}
则仅是文件名。
答案2
您应该能够将 find 输出传递给 shell 命令来执行此操作。
find . -type f -name \*.docx -exec sh -c 'echo libreoffice --convert-to-doc {} --outdir $(dirname {})' \;
@EdgarMagallon 评论中的建议实际上比我的更简单。当然,对于这个用例,我会建议他的命令。
答案3
用-execdir
代替-exec
问题就解决了:
find . -type f -name "*.docx" -execdir libreoffice --convert-to doc {} \;
答案4
使用--output-dir
或将目录更改为找到文档的目录。下面,我将展示如何在不使用 的非标准(但普遍实现)-execdir
谓词的情况下完成此操作find
。
这会将找到的文件的路径名传递给一个简短的内联脚本来迭代它们。对于每个找到的名称,脚本都会更改到找到该文件的目录,然后在那里进行转换。这cd
是在子 shell 中执行的,因此脚本其余部分的环境不受影响。
find . -name '*.docx' -type f -exec sh -c '
for pathname do
( cd "$(dirname "$pathname")" && libreoffice --convert-to doc "$(basename "$pathname")" )
done' sh {} +
以下类似但不更改工作目录。相反,它使用--outdir
选项来指定写入转换后的文档的目录路径。
find . -name '*.docx' -type f -exec sh -c '
for pathname do
libreoffice \
--convert-to doc "$pathname" \
--outdir "$(dirname "$pathname")"
done' sh {} +
在上面的 shell 代码中,"$(dirname "$pathname")"
可以替换为"${pathname%/*}"
(删除"$pathname"
最短后缀字符串匹配/*
),同时"$(basename "$pathname")"
可以替换为"${pathname##*/}"
(删除"$pathname"
最长前缀字符串匹配*/
)。