Shell 脚本:查找特定子目录,进入其中并执行命令

Shell 脚本:查找特定子目录,进入其中并执行命令

我想创建一个脚本,查找子目录中的所有 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 -execdirfind -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(每个匹配对象一个)将独立启动并更改其目录。
  • 我假设pandocsupports--是选项标记的结尾。如果"$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 {/} )'

相关内容