我想创建一个脚本,查找子目录中的所有 Markdown 文件实例,使用 进入这些实例cd
,然后对它们执行一些命令。目前我有:
#!/bin/bash
for file in `find . -name "*.md" -type f`; do
cd `dirname $file` && pandoc -s -o "${file%.md}.tex" "$file"
cd `dirname $file` && pandoc -s -o "${file%.md}.pdf" "$file"
done
使用以下方式pandoc -s -o example.md example.pdf
从 Markdown 文件生成 PDF潘多克。
请注意,我需要cd
进入这些目录,因为我的 Markdown 文档中有相对路径,只有在此特定目录中执行时 pandoc 才能正确检测。
不幸的是,它不起作用并抛出这个错误:
pandoc: ./example_directory/example_file.md: openFile: does not exist (No such file or directory)
编辑:我是 shell 脚本的初学者,请考虑一下:)
答案1
您find
将返回相对路径,例如,./example_directory/example_file.md
因为您告诉它从哪个路径开始.
是相对的。进入正确的目录后,cd
此路径不再有效。您需要basename
或"${file##*/}"
删除它的前导部分。
但还存在其他问题:
- 您的脚本永远不会
cd
返回;下一个脚本cd
将尝试根据相对路径更改目录,从错误的地方开始 - 并且它将失败。 for file in `find . -name "*.md" -type f`; do
是错误的。这是Bash 陷阱。
正确的方法是使用find -execdir
或find -exec
。POSIX 只要求后者。因为无论如何启动 shell 都是好的(从 这样的语法中受益${file%.md}.tex
),我们可以使用find -exec
以实现可移植性,然后cd
在调用的 shell 中使用:
find . -name "*.md" -type f -exec sh -c '
cd "${1%/*}" || exit 1
file="${1##*/}"
pandoc -s -o "${file%.md}.tex" -- "$file"
pandoc -s -o "${file%.md}.pdf" -- "$file"
' sh {} \;
笔记:
- 此代码的大部分是“嵌入”到
-exec
子句中的单引号 shell 脚本。 - 无需
cd
返回,因为每个 shell(每个匹配对象一个)将独立启动并更改其目录。 - 我假设
pandoc
supports--
是选项标记的结尾。如果"$file"
扩展为以 开头的字符串,则该标记至关重要-
。否则,这样的字符串将被解释为选项,而不是操作数。 - 如果我们使用
-exec sh -c '…' sh {} +
,单个文件通常sh
会获得多个.md
文件的路径。这应该比我们当前的解决方案表现更好,因为当前的解决方案会为每个匹配的文件生成一个单独的 shell。但为了提供多个文件,内部脚本必须更复杂。我决定使用 KISS(保持简单和愚蠢)。
答案2
如果您不介意并行运行作业:
find . -name "*.md" -type f |
parallel 'cd {//} && ( pandoc -s -o {/.}.tex {/}; pandoc -s -o {/.}.pdf {/} )'