Bourneshell-Skript, aka Bashscript: Rekursive Verzeichnis-Iteration

Gestern Abend, als ich mich mit der AtariFrosch unterhielt, erzählte sie mir von ihrer Änderung des Encodings auf ihrer Website. Sie sagte, dass man das zwar mit „iconv“ machen könne, dies es aber erforderlich macht, jede Datei einzeln auf zu rufen. Außerdem sollte die jeweils erste Zeile(ein <?xml> mit dem charset ISO) entfernt werden. Perfekt für ’sed‘ und die möglichkeiten der Iteration der Bourneshell, nicht wahr? 😉 

Problem?
Problem?

Also setzte ich ich ein einfaches Skript auf:

Dass dies nicht rekursiv arbeitet, dürfte allen klar sein. Aber iterativ bearbeteit es zumindest dass erste Verzeichniss.

Nun ist ihre Webseite aber sehr verschachtelt, was die Rekursion erforderlich macht. Da dies nicht „das einfachste“ für mich ungeübten Shellskripter war, würde klar sein. 
Zwischendurch aber kam dass Kommando „find“ auf. Nach mehreren Stunden rumprobiererei, weil ich die Manpages abscannen musste, kam dann folgendes Skript zustande:

Code unter GPLv2

Was macht es genau?
per „find $Files -type f -printf „%p „“ formatieren wir die Ausgabe folgendermaßen:

[/crayon]
„-type f“ gibt an, dass nur Dateien ausgegeben werden. Der Ausdruck „-printf „%p “ sorgt für die saubere Ausgabe. %p steht für den relativen Pfad vom aktuellen aus. Denn der Shellskript interpreter kann nur so über die Liste iterieren. Das Problem, dass die Dateien nicht mit dem relativen Pfad angegeben werden können(siehe Ausgabe von ls -R *), wäre also gelöst.

Danach wird nur noch geprüft, ob die Datei auch wirklich eine Datei ist(im Fall, dass ich mich getäuscht hätte mit der Formatierungs- und Typangabe), und danach die Kommandos ausgeführt.

…löscht die erste Zeile(‚1d‘, „delete first line“), schreibt ein Backup in die Datei $f.back und das Ergebniss(löschen der ersten Zeile) wird zurück in die Datei $f geschrieben.Fuck yeah! Fuck yeah!

Für die Lösung habe ich mehrere Stunden gebraucht, weil ich Intelligenzbestie es erstmal mit ls -R versuchen musste. Dass man dabei nur mal „eben“ in die Manpages schauen sollte, zeigt auch dieser Fall. Nichts lehrt uns mehr, als etwas selbst zu machen. So habe ich deutlich gemerkt, was der „richtige“ Weg ist, oder eher der Weg, welcher mir am meisten bringt. 🙂

15 Gedanken zu „Bourneshell-Skript, aka Bashscript: Rekursive Verzeichnis-Iteration

    1. *grins* Ich wusste jetzt nicht, worrauf das bezogen ist. Es geht ja um die allgemeine rekursive Funktion durch Verzeichnisse mit dem Shellskript. convmv kannte ich jetzt bsp. nicht. 😉

  1. Sollte auch in einer etwas kompakteren Form funktionieren:

    find test -type f -exec sh -c „echo ‚Processing File: {}‘; iconv -f ISO-8859-1 -t UTF-8 {} -o {}; sed -i‘.bak‘ ‚1d‘ {}; rm {}.bak; echo ‚File {} finished'“ ;

    Mittels „exec“ kann man direkt ein Kommando ausführen lassen (hier: sh). Die geschweiften Klammern („{}“) werden durch den gefundenen Dateinamen ersetzt.

    Dein Skript ist natürlich etwas lesbarer als so ein Einzeiler 😉

  2. Mein Kommentar von gestern, in dem ich einige sehr hilfreiche Links gepostet habe, wie man gute, portable Shellskripte schreibt, scheint ja entweder nicht freischaltungswürdig, oder wurde gelöscht?

    Sehr schade…

    1. Hmm.. Ich hab den nicht finden können, den Kommentar. Evtl. ist der mit den ganzen Bots ausversehen mit im Spam gelandet, was natürlich passieren kann. Wenn Du noch in ungefähr weißt, was Du schriebst, schiebs doch nochmal rein, ich achte dann nochmal ein bisschen mehr darauf.

  3. Warum einen Backupfile erzeugen, wenn er doch sowieso gleich gelöscht wird? Ist das nicht genau das was sed -i  (ohne .bak) alleine macht?

    1. Hab ich direkt von hier reinkopiert; Das Backupfile war ursprünglich dazu da, um zur Not das ganze wiederherstellen zu können, entsprechend kam das rm erst, als ich es „finalisiert“ hatte. Das war wohl ein überrest… 🙂

  4. es ist gar nicht nice, das ganze in eine Forschleife zu packen, es geht schief, da entweder irgendwas in Dateinamen termeniert oder die Zeilenlänge der Zeichen, die find liefert, für die Bash zu groß wird.

     

  5. Zwei kleine anmerkungen
    1. Dein Script läuft auch unter ner Bourn-Shell. Warum erzingst du im Shebang die bash?
    2. Das printf %p im find ist föllig überflüssig, da du es in eine Umgebungsvariable speicherst und diese später in einer schleife ausliest. Wenn du das wegläst funktionier das script auch auf system deren find keine printf option hat

    Philipp

    1. Die Shebash ist für mich Lokal; Ich hab das Ursprungsskript halt reinkopiert. 😉

      Du meinst das „-printf „%p „“? Dass hat was mit der Iteration zu tun. Wenn Du dass ganze mit n’s bekommst, iteriert der nicht durch die Liste.(zum. nicht bei mir, hab es ausprobiert grade..)

      1. also dass mit dem nicht darüberitterieren ist komish, ich hab das gerade auch ausprobiert und es funktioniert wunderbar. Egal mit welcher shell (sh (unter freebsd), bash und zsh)
        Am Shebang stören mich einfach zwei dinge: erstens nicht jedes system hat die bash instaliert, aber viele leute gehen davon aus und setzen den shebash darauf ohne überhaubt die bash zu benutzen. Zweitens die bash ist nicht zwingend unter /bin/bash bei mir findet man sie in /usr/local/bin/ wo sie auch hingehört.

        1. Moin,
          jow, stimmt. Aber ich nutze die für die Bash, nicht für die ZSH, nicht für die CSH, und nicht für die TCSH – weshalb es mit dem Shebang dort läuft 🙂

          Aber ja, das mit dem Iterieren ist komisch. Ich gucke mal, was ich hätte falsch machen können. Wenn ich etwas finde, lass ich diese erfahrung in mein nächstes Skript einfließen 🙂

Kommentar verfassen