映射文件树,保留结构

映射文件树,保留结构

我有一个文件树,如下所示:

$ tree src
src
├── bible
│   ├── index.md
│   └── README.md
├── index.md
└── other.md

我想通过pandoc(1)以下方式将此文件树中的每个 Markdown 文件渲染为 HTML:保留结构

这个新的文件树应该以 为根out,如下所示:

$ tree out
out
├── bible
│   ├── index.html
│   └── README.html
├── index.html
└── other.html

理想情况下,我想通过make(1).这是我到目前为止所拥有的:

SRC_DIR=src
OUT_DIR=out

.PHONY: all
all: $(SRC_DIR)/*.md
    find . -name "*.md" -exec pandoc '{}' -o '{}'.html \;
    find -name "*.html" -exec bash -c 'mv {} $(OUT_DIR)/`dirname {}`/`basename {} .md.html`.html' \;
    # mv $(SRC_DIR)/*.html $(OUT_DIR)
    firefox $(OUT_DIR)/index.html

.PHONY: clean
clean:
    rm $(OUT_DIR)/*.html

这失败了:

$ make
find . -name "*.md" -exec pandoc '{}' -o '{}'.html \;
find . -name "*.html" -exec bash -c 'mv {} `basename {} .md.html`.html' \;
mv src/*.html out
mv: cannot stat 'src/*.html': No such file or directory
make: *** [Makefile:8: all] Error 1

答案1

对于中或以下某处的单个文件的路径.md名:$pathnamesrc

name=$(basename "$pathname" .md)
destdir=out/$( dirname "${pathname#src/}" )
mkdir -p "$destdir" && pandoc -o "$destdir/$name.html" "$pathname"

这里,basename "$pathname" .md将是不带文件.md名后缀且不带任何目录路径的文件名(例如READMEsrc/bible/README.md,将是不带初始目录名${pathname#src/}的文件路径名,并将设置为目标目录路径名(交换为,无最终文件名组件,例如) 。最后,我们让write to (如果目标目录创建成功)。src/$destdirsrc/out/out/biblesrc/bible/README.mdpandoc$destdir/$name.html

您可以对.md目录结构中的所有文件运行此命令:

find src -type f -name '*.md' -exec sh -c '
    for pathname do
        name=$(basename "$pathname" .md)
        destdir=out/$( dirname "${pathname#src/}" )
        mkdir -p "$destdir" && pandoc -o "$destdir/$name.html" "$pathname"
    done' {} +

这是循环中的同一组命令。我们让find循环使用在下面找到的路径名src(另请参见了解“find”的 -exec 选项)。

测试:

$ tree -F
.
`-- src/
    |-- bible/
    |   |-- README.md
    |   `-- index.md
    |-- index.md
    `-- other.md

2 directories, 4 files

(这里正在运行命令)

$ tree -F
.
|-- out/
|   |-- bible/
|   |   `-- README.html
|   |-- index.html
|   `-- other.html
`-- src/
    |-- bible/
    |   |-- README.md
    |   `-- index.md
    |-- index.md
    `-- other.md

4 directories, 7 files

如果您想使用您的SRC_DIRMakefileOUT_DIR变量:

find $(SRC_DIR) -type f -name '*.md' -exec sh -c '
    srcdir=${1%/}; outdir=$2; shift 2
    for pathname do
        name=$(basename "$pathname" .md)
        destdir=$outdir/$( dirname "${pathname#$srcdir/}" )
        mkdir -p "$destdir" && pandoc -o "$destdir/$name.html" "$pathname"
    done' $(SRC_DIR) $(OUT_DIR) {} +

也就是说,在sh -c脚本的命令行上传递 src 和 out 名称,然后在内联脚本中将它们挑选出来。

我不是 100% 确定 Makefile 中的引用是如何工作的,您可能想要转义上面代码中的换行符,或者创建一个单独的小脚本来执行此操作,然后从 Makefile 中调用它。

答案2

尽管 makefile 和 shell 脚本在语法上有相似之处,但它们的区别就像粉笔和奶酪一样不同。

您正在按照 shell 脚本的精神编写 makefile。在 make 中,我们必须考虑关系和依赖关系。 shell 仅在最后阶段作为满足依赖关系的规则才出现。用 make 的话说,这些被称为菜谱。

###### 
SHELL := /bin/sh

SRC_DIR := src
OUT_DIR := out

### recursive glob
**/* = $(foreach i,$(strip \
  $(wildcard $(1:=/*))),$(strip \
  $(call $0,$i,$2) \
  $(filter $(subst *,%,$2),$i)))

MD_FILES = $(call **/*,$(SRC_DIR),*.md)

HTML_FILES = $(subst $(SRC_DIR)/,$(OUT_DIR)/,$(MD_FILES:.md=.html))

.PHONY: all
all: $(HTML_FILES)

.PHONY: make_dir
make_dir: $(OUT_DIR)/

$(OUT_DIR)/%.html: $(SRC_DIR)/%.md |make_dir
  pandoc $< -o $@

$(OUT_DIR)/: $(SRC_DIR)/
  rsync -avz -f"+ */" -f"- *" $< $@

.PHONY: clean
clean:
  rm -f -- $(HTML_FILES)

相关内容