Wozu braucht man eigentlich ein Kommandozeilen-Terminal?

  • Eigentlich sollte ich das [hierhin] posten, aber mein Narzissmus befiehlt mir, zu diesem Thema gleich wieder einen eigenen Thread zu eröffnen. ;)


    Des öfteren werde ich gefragt - auch im VA IRC schon, glaub' ich zumindest - wofür man eigentlich eine Kommandozeile braucht, wenn man alles auf der GUI machen kann. Oftmals habe ich trotz Erfahrung nicht gleich ein passendes Beispiel bei der Hand, und kann dann nur Dinge wie "Für Systemautomation" sagen, worunter sich sowieso keiner was vorstellen kann. Aber gestern gab' es grade eines, und daher poste ich das Mal hier rein.


    Hintergrund: Ich lese Manga, also Comics, wovon einige auch als Webcomics ausgelegt sind, die man sich so runterladen kann (und manchmal dankenswerterweise auch darf). Üblicherweise schmeiß' ich die durchnummerierten Bilder einfach in eine Comicbook Datei (.cbz, dafür reicht ZIP), dann können das alle gängigen Comicbook Readerprogramme auf Windows, macOS, Linux, Android, iOS usw. lesen und im besten Fall optisch ein bisserl so darstellen, als hätte man wirklich ein offenes Heft mit zwei Seiten und Falz vor sich auf dem Schirm (Pixel Shader Galore).


    Alles easy. Dafür braucht man i.d.R. nichts extra, außer man hat einen Titel mit wirklich vielen .jpg oder .png Files. Aber ein Webcomic hat mich da vor ein kleines kosmetisches Problem gestellt, hier'n Beispiel:


    Im Eve Online Slang würde man dazu "fucking vertical" sagen. Teilweise sind die Strips noch viel "höher" als dieser.


    Ein Überblick - die Strips sehen zum größten Teil so aus:


    Vertikal! - Was in Eve Online cool sein mag, ist beim Lesen von Manga-/Comic-Strips auf Breitbildschirmen etwas sperrig


    Das paßt mir so überhaupt nicht, weil selbst bei zwei Seiten nebeneinander geht davon mehr als der halbe Bildschirm ungenutzt flöten, bei 16:10 schon, bei 16:9 sowieso. Rendert der Reader auch noch einen virtuellen Falz rein, ist noch mehr weg, weil die Strips keinen umgebenden weißen Rand haben, wie meist üblich. Man kann dann reinzoomen, aber dann muß man halt vertikal scrollen. Oder man hat halt zwei dünne Bänder runter und links und rechts dicke schwarze Flächen => Wäh. War mir schon wieder Mal nicht gut genug.


    Anzahl der Einzelbilder in dem Fall: Mit 2.541 nicht so wenige, verteilt über 125 Kapitelordner, pro Kapitel nummeriert von 001.jpg .. nnn.jpg.


    Meine Idee: Per Schleife drüber, die Bilder linear durchnummerieren, dann in 5er Gruppen zusammenfassen, und 5 Einzelbilder jeweils zu einem geblockten Bild zusammenstoppeln, und so neu abspeichern. Sollte von der Bildgröße ziemlich perfekt zu 16:10 passen.


    Ich habe nicht die mindeste Ahnung, wie man so etwas z.B. unter Windows mit einem GUI Programm anstellt, selbst per Corelscript in meinem Photopaint ist das denke ich zu anspruchsvoll. Vielleicht kann Photoshop oder sonst ein Programm von Adobe sowas? Wär spannend zu wissen. Ich jedenfalls reiß' erst Mal die Shell auf, hier unter Linux mit der Bash (Powershell-Äquivalent wäre interessant! Da kenn ich mich leider nix aus).


    Erst Mal der Versuch sämtliche Strips über alle Kapitel durchlaufend zu nummerieren, damit man besser damit arbeiten kann, erst Mal Dryrun (hier zusammengekürzt für weniger Textmüll):

    Code
    1. $ k=0; for i in *; do for j in $i/*; do k=$((k+1)); echo Chapter: $i. Strip per chapter: $j. New, global strip number: $k; done; done; unset k;
    2. 000/001.jpg
    3. Chapter: 000. Strip per chapter: 000/001.jpg. New, global strip number: 1
    4. 000/002.jpg
    5. Chapter: 000. Strip per chapter: 000/002.jpg. New, global strip number: 2
    6. 001/001.jpg
    7. Chapter: 001. Strip per chapter: 001/001.jpg. New, global strip number: 3
    8. 001/002.jpg
    9. Chapter: 001. Strip per chapter: 001/002.jpg. New, global strip number: 4


    Mh, das funktioniert schon Mal. Kapitel 000, Strip 002 wird zu Bild 2, Kapitel 001 Strip 001 wird zu Bild 3 usw.. Also machen wir statt dem echo ein copy, um die ganzen Bilder durchnummeriert in einem Zielordner zu haben, noch ein One-Liner:

    Code
    1. $ k=0; for i in *; do for j in $i/*; do k=$((k+1)); cp $j ../output/$k.jpg; done; done; unset k;


    Besser lesbar so:

    Code
    1. k=0;
    2. for i in *; do # Durchlaufe alle Ordner im aktuellen Verzeichnis
    3. for j in $i/*; # Durchlaufe alle Dateien im Subordner $i
    4. do k=$((k+1)); # Erhöhe globalen Bildzähler um 1
    5. cp $j ../output/$k.jpg # Kopiere lokale Dateien mit neuer globaler Nummerierung nach ../output/
    6. done;
    7. done;
    8. unset k


    Resultat, der Unterordner ../output/ ist jetzt mit 1.jpg bis 2541.jpg befüllt. Soweit so gut. Als nächstes ein Versuch den Batzen in dem Ordner per Modulo (Rest einer Division) in 5er Gruppen zusammenzufassen, hier Mal über die ersten 30 Bilder:

    Code
    1. $ j=0; for ((i=5; i<=30; i++)); do if [ $((i % 5)) = 0 ]; then j=$((j+1)); printf "Grouped file $j: "; echo $(eval echo {$((i-4))..$i}.jpg); fi; done; unset j;
    2. Grouped file 1: 1.jpg 2.jpg 3.jpg 4.jpg 5.jpg
    3. Grouped file 2: 6.jpg 7.jpg 8.jpg 9.jpg 10.jpg
    4. Grouped file 3: 11.jpg 12.jpg 13.jpg 14.jpg 15.jpg
    5. Grouped file 4: 16.jpg 17.jpg 18.jpg 19.jpg 20.jpg
    6. Grouped file 5: 21.jpg 22.jpg 23.jpg 24.jpg 25.jpg
    7. Grouped file 6: 26.jpg 27.jpg 28.jpg 29.jpg 30.jpg


    Na wer sagt's denn! Damit kann man schon Mal weiterarbeiten. Wieder in lesbarerer Darstellung mit Kommentaren:

    Code
    1. j=0;
    2. for ((i=5; i<=30; i++)); do # Zähle von 5 bis 30
    3. if [ $((i % 5)) = 0 ]; then # Wenn Zähler teilbar durch 5..
    4. j=$((j+1)) # Erhöhe 5er Gruppenzähler um 1
    5. printf "Grouped file $j: " # Ausgabe der Gruppennummer
    6. echo $(eval echo {$((i-4))..$i}.jpg) # Ausgabe einer Bildnummer und der 4 vorangehenden Bilder (=Gruppe)
    7. fi;
    8. done;
    9. unset j;


    Jetzt geht's an's eingemachte. Dateien von A nach B kopieren ist ja schön und gut, aber ich will ja Bilder zusammenfügen. Dafür gibt's auf unixoiden Systemen dankenswerterweise die ImageMagick Bibliotheken plus zugehöriger Kommandozeilentools (Auch für Windows zu bekommen). Das beste für's Zusammenstückeln dürfte wohl der ImageMagick Befehl "montage" sein (sagen zumindest irgendwelche Internetmenschen), also habe ich das erstmals ausprobiert. Kurz Doku lesen und auf geht's mit folgenden Parametern:

    • -tile 5x1: Füge Bilder in 5 Spalten in einer Zeile zusammen
    • -background '#111111': Hintergrundfarbe, sehr dunkles grau, fast schwarz (für die Ränder)
    • -geometry +10+10: Ränder zwischen den Bildern, 10 Pixel um jedes Einzelbild


    Geschrieben werden die Daten in einen neuen Ordner ../concat/. Soweit so gut, schicken wir das Trumm los:

    Code
    1. $ j=0; for ((i=5; i<=11; i++)); do if [ $((i % 5)) = 0 ]; then j=$((j+1)); montage $(eval echo {$i..$((i-4))}.jpg) -quality 95 -tile 5x1 -background '#111111' -geometry +10+10 ../concat/$(printf "%04d" $j).jpg; fi; done; unset j;


    Der fügt die ersten 5 Bilder zusammen, und speichert das unter ../concat/0001.jpg, dann die nächsten 5 unter ../concat/0002.jpg und so weiter, bis (in meinem Fall) ../concat/0508.jpg. Eigentlich hätten dreistellige Dateinamen gereicht, najo. Übrigens habe ich auch Mal versucht alle 508 Prozesse komplett parallel loszuschicken, anstatt auf nur einem Kern zu rechnen. Aber das war dann doch etwas zuviel, mußte den Rechner resetten. Die Bilder werden übrigens "verkehrt" gestoppelt, sodaß man von rechts nach links lesen muß; Das ist Absicht, weil es sich um ein ursprünglich japanisches Medium handelt.


    Hier wieder besser lesbar und kommentiert, der Teil:

    Code
    1. j=0
    2. for ((i=5; i<=2541; i++)); do # Zähle von 5 bis 2541 (Weil wir die Bilder vom aktuellen rückzählend lesen)
    3. if [ $((i % 5)) = 0 ]; then # Wenn Zähler teilbar durch 5
    4. j=$((j+1)) # Erhöhe 5er Gruppenzähler um 1
    5. # Füge die aktuelle 5er Gruppe aus 5 Einzelbildern horizontal mit Abstand 10 links und 10 rechts zusammen, und speichere 4-stellig nummeriert ab:
    6. montage $(eval echo {$i..$((i-4))}.jpg) -quality 95 -tile 5x1 -background '#111111' -geometry +10+10 ../concat/$(printf "%04d" $j).jpg
    7. fi;
    8. done;
    9. unset j


    Also bei Nutzung von nur einem Kern hat er schon ein bißchen gebraucht, um die 2.540 Einzelbilder zu 508 Gruppenbilder zusammenzufügen und als JPEGs zusammenzuspeichern. Auf einem i7 980X hat das 2 Minuten und 34 Sekunden gedauert. Es "schlau" zu parallelisieren war mir zu aufwendig. "Scheiß der Hund drauf", wie meine Oma zu sagen pflegt.


    Das Ergebnis im Überblick (Das ist eine recht kleine Bilddatei, daher nicht als Thumbnail):


    Sieht aus, als ob's halbwegs richtig wär...



    Noch zwei Stichproben (Hier wäre PNG wohl auch die bessere Wahl gewesen, das werde ich noch versuchen, aber was soll's erst Mal für's Erste):


       

    Mh jo, ich denke das ist einigermaßen brauchbar, so kann man das in ein Comicbook-Format speichern, und angenehmer lesen



    Jetzt könnte man natürlich argumentieren, daß dieser Anwendungsfall nur eine dumme kleine Spielerei ist, und das wäre schon auch nicht so ganz falsch. Aber da spielt man halt Mal 20 Minuten auf'm Terminal herum, und hat über 2.500 Bilddateien automatisch durchverarbeitet - manuell wäre das ein Alptraum gewesen. Und klar - derartige Automatismen lassen sich auch für richtige Arbeit mannigfaltiger Natur nutzen, und können einem das Leben ungemein erleichtern.


    Und z.B. dafür braucht man dann die Kommandozeile - also ich zumindest.


    Den Thread stelle ich einfach Mal so her, wenn ich auf die Frage "wofür braucht man ein Terminal" Mal wieder keine schnelle Antwort parat habe. ;)


    Mich würde jetzt wirklich interessieren, wie ein Windows Benutzer ohne Kommandozeilenerfahrung mit dem Fall hier umgehen würde. Vielleicht gibt's die GUI Werkzeuge für gerade diese Anwendung ja eh schon, und ich kenne sie nur nicht... Bin da nicht gaaanz so bewandert.

    1-6000-banner-88x31-jpg

    Stolzer Besitzer eines 3dfx Voodoo5 6000 AGP Prototypen:

    • 3dfx Voodoo5 6000 AGP HiNT Rev.A-3700 (defekt)

    [//wp.xin.at] - No RISC, no fun!

    QotY: Girls Love, BEST Love; 2018 - Lo and behold, for it is the third Coming; The third great Year of Yuri, citric as it may be!

    Edited 3 times, last by GrandAdmiralThrawn ().

  • Der Mann hat einfach zu viel Zeit.....

    TUSL2-C, PIII-S 1,4GHz, 512MB, Voodoo3 3000 AGP, SB Live!
    TUSL2-C, PIII-S 1,4GHz, 512MB, Voodoo3 3000 AGP, SB Live!
    CUSL2-C, PIII 933MHz, 512MB, Millennium II AGP 4MB, 2x Monster II 12MB, SB Live!
    CUSL2-C, PIII 933MHz, 512MB, Millennium II AGP 4MB, 2x 3D Blaster Voodoo² 12MB, SB Live!
    P3B-F, PIII 800MHz, 512MB, G400 Max 32MB AGP, 2x Monster II 12MB, SB AWE64 Gold
    P2B-F, PIII 600MHz, 512MB, G200 8+8MB AGP, 2x Monster II 8MB, SB 32 PnP

  • Wieso Zeit? Das ging schnell. Darum geht's ja. Den schnellsten Weg zu finden, um etwas zu erledigen, das man machen will, vor allem wenn das zu lösende Problem ein wenig größer wird. Gesamte investierte Zeit waren wohl 20-30min für die Shell (weil ich nicht so gut bin, wie ich selber oft glaube daß ich wäre) und die paar Minuten für die Ausführung.


    Wenn ich das mit der Hand in meinem Corel PhotoPaint gemacht hätte, wäre ich wahrscheinlich vor der Fertigstellung noch wahnsinnig geworden.


    Da gibt's ein paar interessante Aussagen dazu. Dinge manuell zu machen ist oft schneller, wenn die Probleme sehr klein sind. Aber wenn die Probleme wachsen (und das tun sie leider sehr gerne, z.B. von 100 Bildern zu 10.000 oder 100.000), dann wächst der Aufwand ins Unermeßliche. Klar, für nur sagen wir 10 Bilder eine Automatisierungslösung zu bauen mag hirnrissig erscheinen, wenn das 30min kostet.


    Aber dafür funktioniert die selbe Lösung auch, wenn es plötzlich 3 Millionen Bilder sind, und das richtig schnell.


    Darin liegt imho die Effektivität der Kommandozeile, und das wollte ich hier einfach nur Mal festhalten.


    Umlüx : Tu ned heucheln da! Du weißt genau was ich meine!! ;) Ich glaub' mehr muß man ned sagen. Zu Lightroom haben wir ja im IRC gesprochen: Fähig, aber eventuell nicht ganz so flexibel? Ich hab's selber leider nicht, jetzt kann ich dazu nichts im Detail sagen, du bist der Lightroom User.


    Edit: Ich glaube den Thread zu eröffnen hat in Summe sogar mehr Zeit gekostet, als die Lösung zu bauen. Zum Glück bin ich eine der seltsamen Personen, die es mögen, Dinge zu dokumentieren.


    Edit 2: Weil du unseren Erretter und Heiland Jesus angesprochen hast, der ist leider grade beschäftigt:


    Für die Erzeugung dieses durch historische Originalquellen dokumentierten Abbilds wurden keinerlei Automatismen unter Linux oder UNIX genutzt

    1-6000-banner-88x31-jpg

    Stolzer Besitzer eines 3dfx Voodoo5 6000 AGP Prototypen:

    • 3dfx Voodoo5 6000 AGP HiNT Rev.A-3700 (defekt)

    [//wp.xin.at] - No RISC, no fun!

    QotY: Girls Love, BEST Love; 2018 - Lo and behold, for it is the third Coming; The third great Year of Yuri, citric as it may be!

    Edited 3 times, last by GrandAdmiralThrawn ().

  • Ich meinte Deinen Post hier.

    TUSL2-C, PIII-S 1,4GHz, 512MB, Voodoo3 3000 AGP, SB Live!
    TUSL2-C, PIII-S 1,4GHz, 512MB, Voodoo3 3000 AGP, SB Live!
    CUSL2-C, PIII 933MHz, 512MB, Millennium II AGP 4MB, 2x Monster II 12MB, SB Live!
    CUSL2-C, PIII 933MHz, 512MB, Millennium II AGP 4MB, 2x 3D Blaster Voodoo² 12MB, SB Live!
    P3B-F, PIII 800MHz, 512MB, G400 Max 32MB AGP, 2x Monster II 12MB, SB AWE64 Gold
    P2B-F, PIII 600MHz, 512MB, G200 8+8MB AGP, 2x Monster II 8MB, SB 32 PnP

  • Ok jo, verstehe. Aber wie gesagt, jetzt hab' ich was zum Verlinken, wenn ich die Frage Mal wieder gestellt bekomme. ;)

    1-6000-banner-88x31-jpg

    Stolzer Besitzer eines 3dfx Voodoo5 6000 AGP Prototypen:

    • 3dfx Voodoo5 6000 AGP HiNT Rev.A-3700 (defekt)

    [//wp.xin.at] - No RISC, no fun!

    QotY: Girls Love, BEST Love; 2018 - Lo and behold, for it is the third Coming; The third great Year of Yuri, citric as it may be!