CSV-Datei mit dem Automator-Dienst aufteilen (Finder-Kontextmenü)

Ich versuche, einen Automator- Dienst für das Rechtsklick-Kontextmenü von Finder zu erstellen, der jede ausgewählte CSV-Datei aufteilen kann, während der ursprüngliche Header oben in jeder Datei kopiert wird.

Mein aktueller Versuch besteht darin, Automator dazu zu bringen, dieses Bash-Shell-Skript auszuführen :

#!/bin/bash

FILE=$(ls -1 | grep MY_CSV_FILE.csv)
NAME=${FILE%%.csv}

head -1 $FILE > header.csv
tail -n +2 $FILE > data.csv

split -l 50 data.csv

for a in x??
    do
        cat header.csv $a > $NAME.$a.csv
    done

rm header.csv data.csv x??

Dieses Skript wird in neue Dateien mit maximal 50 Zeilen aufgeteilt MY_CSV_FILE.csv, während der ursprüngliche Header am Anfang jeder Datei kopiert wird. An die neuen Dateien wird der ursprüngliche Name mit xaa, xab, xacusw. angehängt.

In Bezug auf die Automator-Einrichtung ist dies der Dienst, an dem ich derzeit arbeite. Das Problem im Moment ist, dass ich die ausgewählte Datei im Finder nicht an das Bash-Skript übergeben kann.

Geben Sie hier die Bildbeschreibung ein

Beachte das:

  • Dienst empfängt: Dateien oder Ordner in Finder.app .
  • Übergeben Sie die Eingabe an das Shell-Skript: als Argumente .
  • Ich habe #!/bin/bashoben aus dem Shell-Skript entfernt und die Shell auf: /bin/bash gesetzt .
  • Ich wechselte MY_CSV_FILE.csvfür "$f"– nicht sicher, ob das richtig ist.

Muss ich auch den Pfad mit so etwas wie "$@"für die Eingabedatei und die resultierenden Ausgabedateien angeben? Ich habe so etwas noch nie gemacht, also bin ich mit dieser Variable nicht wirklich vertraut und "$f"was das betrifft.

Wie könnte ich das zum Laufen bringen? Ich möchte, dass die resultierenden Dateien im selben Ordner erscheinen wie die Datei, die ich über das Finder-Rechtsklickmenü zum Ausführen des Dienstes auswähle. Noch besser wäre es, wenn der Dienst nur csv-Dateien akzeptieren würde.

Geben Sie hier die Bildbeschreibung ein

Können Sie Ihre Frage bearbeiten, um zu verdeutlichen, was an Ihrem versuchten Ansatz nicht funktioniert? Das heißt, erhalten Sie eine Fehlermeldung? Oder funktioniert es, aber nicht so, wie Sie es sich wünschen? Oder möchten Sie, dass es zusätzlich zu dem, was es derzeit tut, etwas tut? Etwas anderes? Können wir auch davon ausgehen, dass das tatsächliche Shell-Skript, auf das Sie verweisen, funktioniert, oder ist das Ihr Problem?
@Monomeeth Ein sehr gültiger Punkt, tut mir leid. Beim Ausführen des Dienstes wurde ein macOS-Fehlerfeld mit der Aufschrift „Shell-Skriptfehler“ oder so ähnlich angezeigt. Es hat nicht annähernd zum Erfolg geführt. Ich habe keinen bestimmten Codefehler in Automator gesehen. x??.csvEs scheint auch eine Datei namens in meinem Benutzerordner ( ) erstellt zu haben ~.

Antworten (1)

Ich würde den Code etwas anders schreiben, und hier ist ein Beispiel dafür, wie ich es machen würde:

#!/bin/bash

for f in "$@"; do
    if [[ -f $f ]]; then
        d="$(dirname "$f")"
        n="$(basename "$f")"
        t='/tmp'
        if [[ ${n##*.} =~ [cC][sS][vV] ]]; then
            head -1 "$f" > $t/h.tmp
            tail -n +2 "$f" | split -a 3 -l 50 - $t/tmp.
            i=1
            for s in $t/tmp.a??; do
                fn="$d/${n%.*}.$(printf '%03d' $i).csv"
                if [[ ! -f $fn ]]; then 
                    cat $t/h.tmp $s > "$fn"
                    ((i++))
                else
                    rm $t/h.tmp $t/tmp.a??
                    echo "The file '"$fn"' already exists!"
                    exit
                fi
            done
            rm $t/h.tmp $t/tmp.a??
            echo ''
        fi
    fi
done
  • Wie derzeit codiert, verarbeitet es eine oder mehrere Dateien, die an den Dienst übergeben werden .
  • Stellt sicher, dass das Objekt , auf das reagiert wird, eine Datei und kein Verzeichnis ist .
  • Stellt sicher, dass die Datei die Erweiterung .csv hat (unabhängig von der Groß- und Kleinschreibung der Erweiterung).
  • Erstellt die temporären Dateien in:/tmp
  • Überprüft, ob der Ausgabedateiname nicht bereits existiert, und wenn dies der Fall ist, wird es bereinigt und beendet.
  • Schreibt in eine Datei mit einem numerisch inkrementierten Dateinamen , z. B. file.001.csv, file.002.csvusw., im selben Verzeichnis wie die an den Dienst übergebene (n) Datei(en) .
  • Entfernt die temporären Dateien, die erstellt wurden in:/tmp
  • Wie derzeit codiert, verarbeitet es Dateien mit einer Zeilenzahl von bis zu 49.950, die in Dateien mit 50 Zeilen aufgeteilt werden, ohne den Header zu zählen.
    • Beachten Sie, dass für die Gesamtzeilenanzahl der Quelldatei keine Fehlerbehandlung codiert ist , die jedoch leicht hinzugefügt werden könnte.
    • Oder einfach modifiziert werden, um Dateien mit einer Zeilenzahl von bis zu 499.950 zu verarbeiten, aufgeteilt in Dateien mit 50 Zeilen, ohne den Header zu zählen, indem -a 3der split Befehl in -a 4und '%03d'der printf Befehl in geändert wird '%04d'. Sie würden auch $t/tmp.a??in
      for s in $t/tmp.a??; dound rm $t/h.tmp $t/tmp.a??zu ändern:$t/tmp.a???

Ich würde dem Dienst auch eine Run Apple Script- Aktion mit dem folgenden Code hinzufügen :

on run {input, parameters}
    if (item 1 of input) is "" then
        display notification "Splitting of the target file(s) is finished!" with title "Split CSV File(s)"
    else
        display notification (item 1 of input as string) with title "Split CSV File(s)"
    end if
end run

Dadurch wird die Ausgabe der echo Befehle in der Aktion Shell-Skript ausführen aktiviert , um eine Benachrichtigung anzuzeigen, wenn eine Ausgabedatei bereits vorhanden ist oder wenn die Teilung abgeschlossen ist.

Beachten Sie, dass die Benachrichtigung zwar innerhalb der Aktion „Run Shell Script“ mit ausgeführt werden konnte , ich es jedoch so gemacht habe, da es einfacher zu programmieren war.osascript


Automator-Dienst-Workflow

Dies wurde an einer Datei namens file.csv im Finder getestet , die 200 Zeilen enthält, und die Bilder unten zeigen, was durch den Aktionsteil „Run Shell Script“ des Automator-Dienstes erstellt wurde, wenn er auf der Datei ausgeführt wurde .

CSV-Datei im Finder

Inhalt der geteilten CSV-Datei in TextEdit

Bravo, das ist eine sehr beeindruckende Arbeit und eine massive Verbesserung des ursprünglichen Drehbuchs. Hier gibt es viel auszupacken, also werde ich es rechtzeitig tun müssen, aber ich kann bestätigen, dass der Dienst nach ersten Tests großartig funktioniert. Gibt es aus Neugierde (keine Notwendigkeit) einen Grund, für 49.950 statt 499.950 Zeilen zu codieren, zB Leistung? Letzteres werde ich wohl nie brauchen, aber interessant zu lernen.
@Winterflags, es gibt fast immer mehr als einen Weg, etwas zu tun, und warum ich mit " ... hier ist ein Beispiel ... " begonnen habe . Mit dem Code des OP wurden die geteilten Dateinamen um den Wert von erhöht $a, dh x??, zB xaa, xabusw. Es ist eine persönliche Präferenz für mich, ich möchte einen numerischen Wert in den geteilten Dateinamen, also habe ich es dafür codiert . Im Code des OP for a in x??wäre es fehlgeschlagen, wenn die Quelldatei eine Zeilenzahl von mehr als 49.950 hätte, die in Dateien mit 50 Zeilen aufgeteilt wäre, da x??nur 999 Dateien berücksichtigt werden, wo x???9999 Dateien berücksichtigt werden.
@Winterflags, Sowohl der Code im OP als auch mein Code leiden unter der gleichen fest codierten Einschränkung, da beide davon ausgehen, dass die 999 Dateien, die durch den Befehl erstellt werden, nicht mehr vorhanden sein werden. Also muss entweder das Pad groß genug sein, um split ohne Platz zu bieten zuerst die Berechnungen durchführen oder die Berechnungen können zuerst durchgeführt und so codiert werden, dass sie sich dynamisch anpassen. Es ist weniger Codierung, um das Pad anzupassen, als zuerst die Zeilenanzahl zu überprüfen. Wenn Sie eine sehr hohe Anzahl von Zeilen sicherstellen möchten, erhöhen Sie die Werte noch höher als in meiner Antwort angegeben, damit das Pad mehr als ausreichend ist.
@Winterflags, das Ändern -a 3des split Befehls zu -a 5und '%03d'des printf Befehls zu '%04d'und $t/tmp.a??in for s in $t/tmp.a??; dound rm $t/h.tmp $t/tmp.a??zu $t/tmp.a????, verarbeitet Dateien mit einer Zeilenzahl von bis zu 4.999.950, aufgeteilt auf 50 Zeilendateien. Um es noch einfacher zu machen, $t/tmp.a??kann eingestellt werden $t/tmp.*und dann müssten Sie nur -a 3den split Befehl und '%03d'die printf Befehlseinstellung jeweils auf eine höhere Zahl ändern, zB -a 8und '%08d'werden Dateien mit einer Zeilenzahl von bis zu 4.999.999.950 auf 50 Zeilen aufgeteilt Dateien.
@Winterflags, der wichtigste Punkt ist, ich wollte, dass Sie wissen, dass es keine Fehlerbehandlung gibt und wie Sie anpassen können, was dafür verantwortlich ist. Während ich sagte " ... konnte jedoch leicht hinzugefügt werden. ", hätte das eigentlich " ... konnte jedoch hinzugefügt werden. " heißen und warum das Ändern der Werte wie erwähnt eigentlich am einfachsten ist.