Ich mache oft Operationen wie
paste <(cut -d, -f1 file1.csv) <(cut -d, -f1 file2.csv)
Das ist sehr mühsam mit mehr als ein paar Dateien.
Kann ich diesen Prozess automatisieren, z. B. durch Globbing? Ich kann die cut
Ergebnisse mit speichern
typeset -A cut_results
for f in file*.csv; do
cut_results[$f]="$(cut -d, -f1 $f)"
done
aber ich bin nicht sicher, wie ich von dort aus vorgehen soll.
cat file*.csv | cut -d, -f1 | paste
Tun Sie nicht , was Sie zu archivieren versuchen?Antworten:
Sie können dies mit Globbing automatisieren, insbesondere mit dem
e
Glob-Qualifikationsmerkmal pluseval
, aber es ist nicht schön und das Zitieren ist schwierig:\'…\'
ist ein Code, der für jede Übereinstimmung des Globs ausgeführt werden muss. Es wird mit derREPLY
auf die Übereinstimmung eingestellten Variablen ausgeführt und kann geändert werden.REPLY="<(cut -d, -f1 $REPLY)"
generiert die Zeichenfolge,<(cut -d, -f1 file1.csv)
wenn die Übereinstimmung stimmtfile1.csv
. Die doppelten Anführungszeichen sind erforderlich, damit der Teil nach dem Gleichheitszeichen nicht erweitert wird, wenn dere
Code ausgeführt wird, abgesehen vom Ersetzen des Werts vonREPLY
.Es wäre schöner, die Komplexität in einer Funktion zu verbergen. Minimal getestet.
Beispielnutzung (die Syntax erinnert an
zargs
):quelle
e
Qualifier und tolle Idee, ihn in eine generische "Mapping" -Funktion zu packen.--
als Argument an eines der Dienstprogramme übergeben müssen, aber ich glaube nicht, dass ich auf diesenfind
Syntax zu kopieren und ein Semikolon mit Shell-Ich denke, Ihre erste Zeile ist ungefähr so gut wie es für einen einfachen Einzeiler geht.
Wenn es eine Reihe von Dateien mit allen unterschiedlichen Namen gibt, können Sie die wiederholte Eingabe mit einem einfachen Verlaufserweiterungs-Cheat etwas reduzieren:
Erster Lauf
<(cut -d, -f1
Beachten Sie den nachgestellten Leerzeichen. Beachten Sie auch, dass dieser Befehl eine sekundäre Eingabeaufforderung ausgibt. Drücken Sie einfach Ctrl- C. Der einzige Punkt ist, es dem Verlauf hinzuzufügen.
Nächster Lauf
paste !!file1.csv) !!file2.csv)
Das
!!
wird auf den vollständigen Inhalt des vorherigen Befehlslaufs erweitert, einschließlich des nachgestellten Speicherplatzes. Beachten Sie, dass Sie eine sekundäre Eingabeaufforderung erhalten, wenn Sie die nachfolgenden engen Klammern vergessen. Sie können einfach tippen Ctrl- Cund es in diesem Fall erneut versuchen.Dies ist ein bisschen hackig, aber gut genug für eine einmalige Verwendung. Wenn Sie viel tun, können Sie eine Bash-Funktion schreiben.
quelle
Versuchen Sie es mit awk
oder mit sed einfügen
quelle
Ich lerne gerade
bash
Skripte und dies schien eine ausgezeichnete einfache Aufgabe zu sein, mit der ich üben konnte. Deshalb schrieb ich Folgendes. (Meine andere Antwort gibt den einfachen Hack zur Erweiterung des Verlaufs an, aber dies ist ein vollständiges Skript, und ich hielt es für würdig, eine zusätzliche Antwort zu geben.) Ich glaube, dies ist POSIX-kompatibel und sollte funktionieren#!/bin/sh
, aber nicht 100% sicher. EDIT: Eigentlich ist das=~
nicht POSIX-kompatibel. Sie können diesen Check-out jedoch durchführen undcut
den Fehler zurückgeben lassen.quelle
;
Tabulator, oder wenn die Dateinamen Shell-Sonderzeichen enthalten.${(q)delimiter}
. Wenn Sie Code möchten, der auch in Bash funktioniert, ist es schwieriger. Ich denkequoted_single_quote=\'\\\'\'; delimiter="'${delimiter//'/"$quoted_single_quote"}'"
funktioniert in ksh93, bash und zsh.Unter der Annahme, dass Ihre Argumente zutreffen
"$@"
, glaube ich so etwas wie:Sollte es tun.
quelle
Hier ist eine andere Möglichkeit, die der Antwort von Wildcard sehr ähnlich ist :
Anstelle einer
for
Schleife wird die${^ ... }
Erweiterung verwendet, die Zsh-spezifisch ist.Der Grund
files
, der zuerst zugewiesen werden muss, ist, dass das Globbing immer zuletzt durchgeführt wird. Wennfiles
also automatisch (wie infiles=( *.csv )
) generiert werden muss, wird so etwas${^:-( *.csv )}
erst erweitert, nachdem alle anderen Erweiterungen aufgetreten sind. Wir wollen, dass es zuerst erweitert wird .Die
${^ ... }
Erweiterung bewirkt, dass sich das resultierende Array wie das Ergebnis der Klammererweiterung verhält. Zuweisenx=(a b)
und dann vergleichenecho ${x}y
mitecho ${^x}y
.Das Anführungszeichen ist notwendig, um Zsh dazu zu bringen, den umgebenden Text wie eine wörtliche Zeichenfolge zu behandeln. Andernfalls würde die Befehlszeile an den Leerzeichen aufgeteilt, sodass sich unsere
${^ ... }
Erweiterung auf reduzieren würde""${^ ... }""
. Das heißt, jedes Element würde nur von einer leeren Zeichenfolge umgeben sein. Das ist,und
sind gleichwertig, aber nicht dasselbe wie
Das Zitieren bringt jedoch ein neues Problem mit sich: Die Befehlszeile wird analysiert und aufgeteilt, ohne Rücksicht auf die stattfindende Erweiterung. Das heißt, obwohl wir effektiv eingetreten sind
wie gewünscht wird dies tatsächlich als analysiert
Daher müssen wir
eval
den korrekt geformten Ausdruck neu analysieren. Vergleichen Sie dies, um dies in Aktion zu sehenzu
Ich hoffte , dass eine Kombination von verschachtelten Erweiterungen, die
${ ... :- ... }
Erweiterung und dem Parameter Expansion FlagsQ
,z
und / oders
würde ohne zu einer Neubewertung führeneval
, aber offenbar nicht der Fall ist. Ich wünschte auch, es gäbe einen Weg, das Globbing zu erzwingen, aber auch das scheint unmöglich.quelle
Sie können
awk
die Dateien im Gleichschritt durchlaufen und das interessierende Feld aus jeder Datei melden. Fügen Sie diesen Code beispielsweise in eine Datei eincut_files.awk
Und dann nenne es so
quelle