Unix - Anzahl der Spalten in der Datei


77

Gegeben eine Datei mit Daten wie diese (dh die Datei storage.dat)

sid|storeNo|latitude|longitude
2|1|-28.03720000|153.42921670
9|2|-33.85090000|151.03274200

Was wäre ein Befehl, um die Anzahl der Spaltennamen auszugeben?

dh im obigen Beispiel wäre es 4. (Anzahl der Pipe-Zeichen + 1 in der ersten Zeile)

Ich dachte so etwas wie:

awk '{ FS = "|" } ; { print NF}' stores.dat

Es werden jedoch alle Zeilen anstelle der ersten und für die erste Zeile 1 anstelle von 4 zurückgegeben

Antworten:


117
awk -F'|' '{print NF; exit}' stores.dat 

Beenden Sie einfach gleich nach der ersten Zeile.


3
oderawk -F'|' 'NR==1{print NF}' stores.dat
Jaypal Singh

10
@ JaypalSingh: das liest die ganze Datei - keine Notwendigkeit dafür, besser früh aufhören.
Mat

Beide scheinen dieselbe korrekte Ausgabe zurückzugeben. Gibt es einen Leistungsvorteil von 1 gegenüber dem anderen (oder einen anderen Vorteil)?
Toop

2
@toop: Ja, siehe meinen vorherigen Kommentar. Meine Version liest nur einen Block aus der Datei, Jaypal liest die gesamte Datei.
Mat

1
@Mat Du bist genau richtig! @loop Mat ist absolut korrekt. exitist der richtige Weg, um es zu tun. Sie müssen nicht die gesamte Datei lesen, wenn Sie nur die Anzahl der Spalten wissen möchten. +1 :)
Jaypal Singh

37

Dies ist eine Problemumgehung (für mich: Ich benutze awk nicht sehr oft):

Zeigen Sie die erste Zeile der Datei mit den Daten an, ersetzen Sie alle Pipes durch Zeilenumbrüche und zählen Sie dann die Zeilen:

$ head -1 stores.dat | tr '|' '\n' | wc -l

9
Für Dateien mit vielen Spalten (denken Sie an SNP-Daten) ist dies der richtige Weg. Mats Lösung ergab "awk: Programmlimit überschritten: maximale Anzahl von Feldern = 32767".
Die Unfun Cat

11

Sofern Sie dort keine Leerzeichen verwenden, sollten Sie diese in | wc -wder ersten Zeile verwenden können.

wcist "Word Count", das einfach die Wörter in der Eingabedatei zählt. Wenn Sie nur eine Zeile senden, wird die Anzahl der Spalten angezeigt.


Ich habe versucht: head -1 store.dat | wc -w Aber das gibt nicht zurück, was ich will
toop

Das liegt daran, dass Sie das nicht durch |ein Leerzeichen ersetzen - es wcwerden Wörter gezählt, die durch Leerzeichen getrennt werden müssen. Verwenden Siehead -1 stores.dat | tr '|' ' ' | wc -w
Tom van der Woerdt

2
Bitte fügen Sie der Antwort der Vollständigkeit halber Ihren Kommentar hinzu.
Xofo


2

Perl-Lösung ähnlich der awk-Lösung von Mat:

perl -F'\|' -lane 'print $#F+1; exit' stores.dat

Ich habe dies an einer Datei mit 1000000 Spalten getestet.


Wenn das Feldtrennzeichen ein Leerzeichen (ein oder mehrere Leerzeichen oder Tabulatoren) anstelle einer Pipe ist:

perl -lane 'print $#F+1; exit' stores.dat

1

Wenn Sie Python installiert haben, können Sie versuchen:

python -c 'import sys;f=open(sys.argv[1]);print len(f.readline().split("|"))' \
    stores.dat

In diesem speziellen Fall ist es kürzer, von der Standardeingabe zu lesencat x.txt | python -c "print raw_input().count('|') + 1"
Lie Ryan

kürzer ja, aber nicht schneller, wenn es viele lange Dateien gibt! Ich nahm an, dass er eine schnellere Lösung im Auge von reinen (sicher großen) Datendateien wollte.
Don Frage

1

Dies ist normalerweise das, was ich zum Zählen der Anzahl der Felder verwende:

head -n 1 file.name | awk -F'|' '{print NF; exit}'

1

Wählen Sie eine beliebige Zeile in der Datei aus (im folgenden Beispiel ist es die 2. Zeile) und zählen Sie die Anzahl der Spalten, wobei das Trennzeichen ein Leerzeichen ist:

sed -n 2p text_file.dat | tr ' ' '\n' | wc -l

0

Basierend auf der Antwort von Cat Kerr. Dieser Befehl arbeitet mit Solaris

awk '{print NF; exit}' stores.dat

Und dann sind Sie bei der akzeptierten Antwort ohne das richtige Feldtrennzeichen. Dies würde "1" für die Beispieleingabe zurückgeben.
Benjamin W.

Dies entspricht im Wesentlichen der akzeptierten Antwort ohne Feldtrennzeichen, da Bejamin sagt, dass 1 zurückgegeben wird, jedoch für durch Leerzeichen getrennte Dateien funktionieren sollte.
Discipulus


0

Richtig rein Weg

Unter Bash könnte man einfach:

IFS=\| read -ra headline <stores.dat
echo ${#headline[@]}
4

Viel schneller als ohne Gabeln und wiederverwendbar, wenn Sie $headlinedie volle Schlagzeile halten. Sie könnten zum Beispiel:

printf " - %s\n" "${headline[@]}"
 - sid
 - storeNo
 - latitude
 - longitude

Hinweis Diese Syntax steuert Leerzeichen und andere Zeichen in Spaltennamen korrekt.

Alternative: Starke binäre Überprüfung auf maximale Spalten in jeder Zeile

Was ist, wenn eine Zeile zusätzliche Spalten enthält?

Dieser Befehl sucht nach größeren Zeilen und zählt Trennzeichen :

tr -dc $'\n|' <stores.dat |wc -L
3

Es gibt maximal 3 Trennzeichen, dann 4 Felder.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.