マップファイルツリー、構造の維持

マップファイルツリー、構造の維持

次のファイルツリーがあります。

$ 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/}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_DIRMakefile変数を使用するにはOUT_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の名前を渡し、インラインスクリプトから選択します。

Makefileで引用がどのように機能するかを100%確信できません。上記のコードで改行をエスケープするか、別の小さなスクリプトを作成してそれを実行してから、Makefileから呼び出すことができます。

答え2

構文的類似性にもかかわらず、makefileとシェルスクリプトはチョークとチーズとは異なります。

シェルスクリプトの精神でメイクファイルを作成しています。 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)

関連情報