次のファイルツリーがあります。
$ 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
。$pathname
src
name=$(basename "$pathname" .md)
destdir=out/$( dirname "${pathname#src/}" )
mkdir -p "$destdir" && pandoc -o "$destdir/$name.html" "$pathname"
ここでは、ファイル名のサフィックスがbasename "$pathname" .md
なく、ディレクトリパス(たとえば)がないファイル名に.md
なり、初期ディレクトリ名を持たないファイルパス名になり、宛先ディレクトリパス名に設定されます(最終ファイル名コンポーネントなしで交換されます。について)。最後に(ターゲットディレクトリが正常に作成された場合)への書き込みを許可します。README
src/bible/README.md
${pathname#src/}
src/
$destdir
src/
out/
out/bible
src/bible/README.md
pandoc
$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_DIR
Makefile変数を使用するには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)