Ich habe also eine Textdatei, aus der ich bestimmte Zeilen extrahieren und zählen muss, wie oft eine Zahl in einer bestimmten Spalte vorkommt. Ich habe ungefähr 100 dieser Dateien. Ich kann das in kleinen Schritten erledigen, möchte es aber mit Bash/KSH erledigen:
foreach i *h3
sed '4p;55p;77q;d' $i >> output.txt
end
^^^^dadurch werden nur die Zeilen extrahiert, die ich aus jeder h3-Datei brauche
awk '{print $6}' output.txt | grep 'P2' | wc -l
^^^dadurch wird einfach Spalte 6 aus output.txt extrahiert und gezählt, wie oft P2 in Spalte 6 vorkommt
Gibt es eine Möglichkeit, all dies in einem Bash/Ksh-Skript zu kombinieren?
Antwort1
Wenn ich das richtig verstanden habe:
- Sie möchten zählen, wie oft „P2“ irgendwo im 6. Feld der Zeilen 4, 55 und 77 einiger Dateien (mit dem Namen *h3) vorkommt?
Sie könnten dies mit 1 awk tun:
awk '
( FNR==4 || FNR==55 || FNR==77 ) {
if ( $6 ~ "P2" ) { occurence++ }
}
END {
printf "There was: %d P2 ", occurence
printf " among the 6th field on lines 4,55 or 77 of the *h3 files\n"
}' *h3
Hinweis: Ändern Sie es $6 ~ "P2"
in , $6 == "P2"
wenn Sie eine genaue Übereinstimmung wünschen (anstelle eines grep, wie Sie es in Ihrem eigenen Beispiel verwendet haben, sodass es auch mit Folgendem somethingP2otherthing
und Varianten davon übereinstimmt).
FNR = Anzahl der Datensätze der Datei = Anzahl der Zeilen in der aktuellen Datei (d. h. beginnt in der ersten Zeile jeder Datei wieder bei 1) (Aktuelle Datei, deren Name auch durch die interne Variable „FILENAME“ ermittelt werden kann)
(NR = würde hier nicht funktionieren, da es sich um die (Gesamt-)Anzahl der seit Beginn gelesenen Datensätze handelt (nicht seit Beginn der aktuellen Datei))
Antwort2
Sicher. Hier ist eine Möglichkeit
p2_count=0
for f in *h3; do
for ((n=1; n<=77; n++)); do
IFS= read -r line
if [[ $n == 4|55|77 ]]; then
echo "$line"
set -f
set -- $line
set +f
if [[ $6 == *P2* ]]; then
((p2_count++))
fi
fi
done < "$f"
done > output.txt
echo "saw P2 in 6th column $p2_count times"
Antwort3
Oder mit einemSchlagEinzeiler:
for i in *h3; do sed '4p;55p;77q;d' $i | awk '{print $6}' | grep 'P2'; done | wc -l
Oder kürzer mit grep -c
:
for i in *h3; do sed '4p;55p;77q;d' $i | awk '{print $6}'; done | grep -c 'P2'
Antwort4
Normalerweise, wenn eine Frage lautet: "Wie verarbeite ich eine Reihe von Textdateien mitspezifische(s) Werkzeug(e)in einer Bash-Schleife?", lautet die Antwort teilweise: "Verwenden Sie keine Bash-Schleife, verwenden Sie (einige oder alle) der Tools selbst". Manchmal lautet ein Teil der Antwort sogar: "Verwenden Sie diese Tools nicht, verwenden Sie stattdessen dies".
Was Sie wollen, können Sie allein erledigen awk
, eine Shell-Schleife ist nicht erforderlich. Oder sed
oder grep
oder wc
:
awk 'BEGIN {OFS="\t"}
FNR ~ /^(4|10|17)$/ && $6 ~ /P2/ {count++}
ENDFILE { print FILENAME, count; count=0 }' *h3
Notiz:ENDFILE ist spezifisch für GNU awk
. Es funktioniert nicht mit anderen Versionen von awk
.
Und diese Version druckt auch eine Gesamtsumme aller Dateien:
awk 'BEGIN {OFS="\t"}
FNR ~ /^(4|10|17)$/ && $6 ~ /P2/ {count++; total++}
ENDFILE { print FILENAME, count; count=0 }
END { print "---", total,"total" }' *h3
Der END{}
Block druckt die Gesamtsumme und unternimmt außerdem einen groben Versuch, die tatsächliche Gesamtsumme von allen Dateien zu unterscheiden, die zufällig den Dateinamen „total“ haben. Dies geschieht, indem ---
im ersten Feld, dann die Gesamtsumme und dann die Zeichenfolge total
im dritten Feld gedruckt wird. Dies ist bei weitem nicht perfekt, reicht aber in vielen Fällen aus. Es ist besser, als beispielsweise wc
den Versuch überhaupt nicht zu unternehmen.