맵 파일 트리, 구조 유지

맵 파일 트리, 구조 유지

다음과 같은 파일 트리가 있습니다.

$ 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)

관련 정보