Mit Bash alle Dateien im Ordner durchlaufen

Mit Bash alle Dateien im Ordner durchlaufen

Ich habe eine Reihe von Markdown-Dateien in meinem Ordner, die ich mit Pandoc in HTML konvertieren möchte.

Der Befehl, den ich normalerweise verwende, ist

pandoc Atten.md -f markdown -t html --css pandoc.css -o Atten.html

wobei Atten.mdder Name einer typischen Markdown-Datei ist. Ich möchte jedoch alle Dateien durchlaufen und .md wie oben beschrieben in .html konvertieren. Wie mache ich das in Bash oder Zsh?

Antwort1

Mit find:

find path/to/dir -name "*.md" -type f -exec sh -c '
      pandoc -f markdown -t html --css pandoc.css -o "${1%.*}.html" "$1"
   ' find-sh {} \;

Es sollte in Bash, Zsh und vielen anderen Shells funktionieren. Die einzige Aufgabe der äußeren Shell besteht darin, findmit den richtigen Argumenten ausgeführt zu werden.

Diese Version startet einen einzelnen Prozess, shum so viele Dateien wie möglich zu verarbeiten ( shbei Bedarf werden weitere Prozesse gestartet):

find path/to/dir -name "*.md" -type f -exec sh -c '
      for f; do
         pandoc -f markdown -t html --css pandoc.css -o "${f%.*}.html" "$f"
      done
   ' find-sh {} +

Anmerkungen:

  • Die innere Shell wird nur aufgerufen, weil wir die alte Erweiterung entfernen müssen. Wenn dies nicht erforderlich wäre, … -exec pandoc … -o {}.html {} \;würde wahrscheinlich eine Lösung mit funktionieren. „Wahrscheinlich“, weil POSIX erfordert, nur findein einziges zu ersetzen {}. Es ist eine „Gefälligkeit“ der findvon Ihnen verwendeten Implementierung, wenn etwas anderes ersetzt wird (wie {}.htmloder das zweite Auftreten von {}).
  • -execdiranstelle von -execwäre besser, aber es ist nicht POSIX.
  • -execdir./"$1"würde es uns erlauben , statt "$1"(bzw. ./"$f"statt ) zu verwenden , um zu verhindern, dass es von als Option "$f"interpretiert wird . Ein anderer Ansatz istpandoc--aber ich weiß nicht, ob pandoces das unterstützt. Ich denke, in Ihrem Fall "$1"kann es nicht auf irgendetwas erweitert werden, das mit beginnt, -weil es mit beginnen muss path/to/dir, und wenn path/to/dires mit beginnt -, würde es von findvornherein durch falsch interpretiert werden. Generell ist diese Sorge jedoch berechtigt.
  • Beim pandocAufruf habe ich den Operanden nur deshalb ans Ende verschoben, weil ich die gebräuchlichste Reihenfolge bevorzuge command -options operands.

  • Die Lösung ist rekursiv. Um sie nicht-rekursiv zu machen, geben Sie an -maxdepth 1. Wenn Ihr finddas nicht unterstützt, -maxdepthdann studieren SieDasoder löschen Sie es findund lassen Sie die äußere Shell über die Dateien iterieren:

    # written for Bash
    ( cd path/to/dir || exit 125
    for f in ./*.md ./.*.md; do
        [ -f "$f" ] &&
        pandoc -f markdown -t html --css pandoc.css -o "${f%.*}.html" "$f"
    done )
    

    Spezifische Hinweise zum obigen Code:

    • Die Untershell dient dazu, cdzu arbeiten, ohne die aktuelle Shell zu beeinträchtigen.
    • Wenn cddies aus irgendeinem Grund fehlschlägt, wird der Rest nicht ausgeführt. Dies ist eine gute Vorgehensweise.
    • ./*.mdanstelle von plain *.mdverhindert "$f", dass es später als Option interpretiert wird.
    • ./.*.mdwird hinzugefügt, da ./*.mdes nicht mit den Dotfiles übereinstimmt.
    • [ -f "$f" ]ist zu verhindern
      • Aufrufen pandocvon Verzeichnissen, speziellen Dateien und dergleichen;
      • Aufruf pandocfür „nonexistent“ ./*.md(oder ./.*.md), wenn nichts dem Muster entspricht.
    • Zsh ist etwas anders. Der Code sollte jedoch funktionieren shund da eine Subshell sowieso nützlich ist, würde es keinen großen Unterschied machen, wenn Sie shexplizit von einer beliebigen vernünftigen Shell aus aufrufen würden:

      sh -c 'cd path/to/dir || exit 125
             for …
             done '
      

Antwort2

Sie sollten findund seine verwenden -exec(sieheMann finden):

find YourDirectory -name \*.md | \
  while IFS= read fn; do \
  pandoc ${fn} -f markdown -t html --css pandoc.css -o ${fn%.md}.html ; done

Oder vielleicht -execdir.

Antwort3

Sie können die Datei mit einem for iterieren:

for item in *.md; do CONVERT_FILE_COMMAND $item "$(basename '$item' .md).html; done

verwandte Informationen