Ich habe eine große Anzahl von Dateien in einem bestimmten Ordner. Ich möchte diese Dateien NUR WENN sie in einer Zeile der Spalte 4 mindestens 1 Wert über 0,5 haben, in einen Unterordner verschieben. In einem separaten Befehl möchte ich dasselbe tun, aber mit Dateien, die mindestens 2 Zeilen mit Werten über 0,5 in Spalte 4 haben.
Dies ist das allgemeine Format der Dateien (mit Header):
col1 col2 col3 col4 col5 col6
ABC DEF 5.10 0.94 GHI JKL
MNO PQR 8.31 0.37 STU VWX
ABC DEF 6.49 0.84 GHI JKL
MNO PQR 3.32 0.21 STU VWX
Einige der Zahlen in Spalte 4 sind in wissenschaftlicher Notation: 8.934553871039306e-05
Mit dem folgenden Code habe ich bisher versucht, Dateien mit mindestens einem Wert über 0,5 in Spalte 4 zu verschieben. Dabei werden alle Dateien in den Unterordner verschoben, auch diejenigen, die die Bedingung nicht erfüllen.
#!/bin/bash
find . -type f -exec awk '$4 >= 0.5' {} \; -exec mv -n {} ./NewFolder/ \;
Antwort1
Damit Ihr Befehl funktioniert, müssen Sie awk
mit dem Code 0 beenden, wenn eine Übereinstimmung gefunden wird, oder mit einem Exit-Code ungleich Null, wenn keine Übereinstimmung gefunden wird.
Darüber hinaus sollten Sie die erste Zeile überspringen, da ein nicht numerischer Wert als Zeichenfolge verglichen wird, was zu einer unerwarteten Übereinstimmung führen kann.
find . -type f -exec awk 'FNR==1 {next} $4 >= 0.5 {found=1; exit} END {exit !found}' {} \; -exec mv -n {} ./NewFolder/ \;
Hinweis: Wenn das awk
Skript mit mehr als einer Datei aufgerufen wird, bedeutet der Exit-Code, dass in einer der Dateien eine Übereinstimmung gefunden wurde. Der find
Befehl stellt sicher, dass immer nur eine Datei gleichzeitig an übergeben wird awk
, daher ist dies hier kein Problem.
2. Bearbeitung:
Um Dateien auszuwählen, die mindestens zwei übereinstimmende Zeilen haben, können Sie die Übereinstimmungen zählen.
find . -type f -exec awk 'FNR==1 {next} $4 >= 0.5 {found++; if(found >= 2) exit} END {exit found >= 2}' {} \; -exec mv -n {} ./NewFolder/ \;
Bearbeiten:
Um das Problem zu beheben, dass das Skript Dateien verschiebt, die keinen übereinstimmenden Wert in Spalte 4 haben, können Sie dem awk
Skript Code hinzufügen, um Informationen über die übereinstimmende Zeile auszudrucken. Der folgende Code druckt den Dateinamen, die Zeilennummer und die übereinstimmende Zeile, wenn eine Übereinstimmung gefunden wurde.
find . -type f -exec awk 'FNR==1 {next} $4 >= 0.5 {found=1; printf "%s:%d:%s\n", FILENAME, FNR, $0; exit} END {exit !found}' {} \; -exec mv -n {} ./NewFolder/ \;
Sie erhalten etwas wie
threshold.txt:2:ABC DEF 5.10 0.94 GHI JKL
Ich schlage vor, dies zuerst zu tun, um die Ursache des Problems zu finden.
Wenn es Zeilen gibt, die in Spalte 4 einen nicht numerischen Text haben, werden die Werte als Text verglichen. Dies würde beispielsweise dazu führen, dass "abc"
größer ist als "0.5"
.
Eine weitere mögliche Ursache könnte eine Zeile sein, die in Spalte 1 oder 2 Leerzeichen enthält, was zu einer falschen Zuordnung des Textes zu den Spalten führt.
Falls Spalte 4 nicht numerische Werte enthält und Sie diese Zeilen ignorieren möchten, können Sie eine numerische Interpretation erzwingen, indem Sie den Wert wie 0
in hinzufügen 0 + $4
.
find . -type f -exec awk 'FNR==1 {next} 0 + $4 >= 0.5 {found=1; printf "%s:%d:%s\n", FILENAME, FNR, $0; exit} END {exit !found}' {} \; -exec mv -n {} ./NewFolder/ \;
Wenn das Problem darin liegt, dass Ihre Felder durch Tabulatoren getrennt sind und die Werte Leerzeichen enthalten können, können Sie den Feldtrenner ( -F "\t"
) angeben. Das folgende Skript kombiniert dies mit den anderen Änderungen.
find . -type f -exec awk -F "\t" 'FNR==1 {next} 0 + $4 >= 0.5 {found=1; printf "%s:%d:%s\n", FILENAME, FNR, $0; exit} END {exit !found}' {} \; -exec mv -n {} ./NewFolder/ \;
Antwort2
Das awk
funktioniert nicht wirklich. Es werden alle Dateien gefunden, da die Zeichenfolge col4
Folgendes erfüllt >=0.5
:
$ echo col4 | awk '$1>=0.5'
col4
Sie müssen also den Header überspringen. Sie müssen awk außerdem anweisen, erfolgreich zu beenden, wenn die Datei Ihren Kriterien entspricht, und mit einem Fehler, wenn dies nicht der Fall ist. Etwa so:
find . -type f \
-exec awk -va=1 '{ if($4 >= 0.5 && NR>1){a=0}} END{exit a}' {} \; \
-exec mv -n {} ./NewFolder/ \;
Antwort3
Mit einer For-Schleife können Sie Folgendes versuchen:
for i in *; do # *.extension
[[ -f "$i" && $(awk 'NR>1 && $4 >= 0.5' "$i") ]] && mv "$i" NewFolder/
done
Und für zwei Werte:
for i in *; do # *.extension
[[ -f "$i" ]] && [[ $(awk 'NR>1 && $4 >= 0.5' "$i" | wc -l) -ge 2 ]]
mv "$i" NewFolder
done