2016-07-30 6 views
-1

Meine Frage ist nicht einfach zu fragen ist, versuche ich das Problem mit dem folgenden Beispiel erläutern:Zählen grep Ergebnis arbeiten gewohnt in Bash-Skript

/home/luther/tipical_surnames.txt

Smith 
Johnson 
Williams 
Jones 
Brown 
#Davis 
Miller 
Wilson 
#Moore 
Taylor 
Anderson 

/home /luther/employers.txt

2000 Johnson  A lot-of details/BJC3000,6000, i550    0 
2101 Smith  A lot-of details/BJC3000,6000, i550    0 
2102 Smith  A lot-of details/BJC3000,6000, i550    0 
2103 Jones  A lot-of details/BJC3000,6000, i550    0 
2104 Johnson  A lot-of details/BJC3000,6000, i550    0 
2100 Smith  A lot-of details/BJC3000,6000, i550    0 

habe ich eine Liste mit den beliebtesten Familiennamen und ein anderer mit dem Namen der Arbeitgeber. Lassen Sie uns prüfen, wie viele Menschen die beliebtesten Namen in der Gesellschaft haben, Konsole:

grep -v "#" /home/luther/tipical_surnames.txt | sed -n 1'p' | cut -f 1 
Smith 
grep Smith /home/luther/employers.txt | wc -l 
230 

Arbeit perfekt. können Sie nun die ersten 5 beliebtestenen Namen überprüfen, einen einfachen Bash-Skript verwenden:

#!/bin/bash 
counter=1 
while [ $counter -le 5 ] 
do 
    surname=`grep -v "#" /home/luther/tipical_surnames.txt | sed -n "$counter"'p' | cut -f 1` 
    qty=`grep "$surname" /home/luther/employers.txt | wc -l` 
    echo $surname 
    echo $qty 
    counter=$(($counter + 1)) 
done 

Und das Ergebnis den folgt:

Smith 
0 
Johnson 
0 
Williams 
0 
Jones 
0 
Brown 
0 

Was ist falsch?

Update: Wie ich geschrieben habe ich das Skript auf anderen Computer getestet und alles funktioniert gut. Nachdem ich versuche, die folgen:

[email protected]:/var/www# cat testfile.bash 
#!/bin/bash 
for ((c=1; c<=5; c++)) 
{ 
echo $c 
} 

[email protected]:/var/www# bash testfile.bash 
testfile.bash: line 2: syntax error near unexpected token `$'\r'' 
'estfile.bash: line 2: `for ((c=1; c<=5; c++)) 
[email protected]:/var/www# echo $BASH_VERSION 
4.2.37(1)-release 
[email protected]:/var/www# 

Natürlich auf anderen Computern dies einfach Skript wie erwartet funktionieren, ohne Fehler.

+0

Eine Shell ist eine Umgebung, aus der Werkzeuge aufgerufen werden können, kein Werkzeug zum Bearbeiten von Text. Das Standard-Universal-UNIX-Tool zum Bearbeiten von Text ist awk. Sie haben Probleme, weil Sie das falsche Tool verwenden und es wäre immens kompliziert und ineffizient, das zu tun, was Sie in der Shell robust machen wollen (siehe [why-is-using-a-shell-loop-to-process-text- schlechtes Üben] (http://unix.stackexchange.com/questions/169716/why-is-using-a-shell-loop-to-process-text-considered-bad-practice)). Wirf es weg und beginne mit awk. Präzise, ​​testbare Beispieleingabe und erwartete Ausgabe können wir Ihnen helfen. –

+0

Ich vermute, Sie haben eine Datei mit DOS-Zeilenenden. Sie sehen sie nicht beim Kopieren/Einfügen von Programmausgaben, aber sie werden in der erfassten Variablen vorhanden sein und verhindern, dass das letzte 'grep' irgendwas ergibt. Probieren Sie 'dos2unix' für die Dateien aus. Zur weiteren Problembehandlung enthält das [Stack Overflow 'bash'-Tag-Wiki] (// stackoverflow.com/tags/bash/info) einen detaillierten Abschnitt zu diesem Problem. – tripleee

+0

@Ed Morton Ok, es ist klar, aber ich verstehe immer noch nicht, warum mein Code gut sein wird, wenn ich die $ Nachname-Variable zu einem Wert ersetze. Wie Sie aus dem Ergebnis sehen können, hat die Variable $ name einen guten Wert, wenn ich sie auf den Bildschirm ausgeben möchte. Warum funktioniert dieselbe Variable nicht, wenn ich die Variable $ qty deklariere? – Luther

Antwort

0

Ich bin mir eigentlich nicht ganz sicher. Ich habe Ihr Skript getestet, indem ich es kopiert und eingefügt habe, mit imaginären Daten (/usr/share/dict/words) und es scheint zu funktionieren wie erwartet. Ich frage mich, ob es einen Unterschied zwischen dem Skript, das Sie gepostet haben, und dem Skript, das Sie ausführen, gibt?

Während ich dabei war, habe ich mir die Freiheit genommen, es ein bisschen glatter laufen zu lassen. Beachten Sie, wie Sie in der Schleife die Gesamtheit der Nachnamen-Datei in jeder Iteration lesen? Außerdem kann grep + wc -l durch grep -c ersetzt werden. Ich füge auch -F zum ersten Aufruf von grep hinzu, da das Muster (#) feste Zeichenfolgen ist. Die grep in der Mitarbeiterdatei verwendet \<$name\>, um sicherzustellen, dass wir nur die Johns und no Johnssons erhalten, wenn $nameJohn ist.

#!/bin/bash 

employees_in="/usr/share/dict/words" 
names_in="/usr/share/dict/words" 

grep -v -F "#" "$names_in" | head -n 5 | cut -f 1 | 
while read -r name; do 
    count="$(grep -c "\<$names\> " "$employees_in")" 
    printf "name: %-10s\tcount: %d\n" "$name" "$count" 
done 

Testing es:

$ bash script.sh 
name: A    count: 1 
name: a    count: 1 
name: aa   count: 1 
name: aal   count: 1 
name: aalii   count: 1 

Anmerkung: Ich Einzigen, die in der Zählung, weil das Wörterbuch (nicht überraschend) nur eindeutige Wörter enthält.

+0

Vielen Dank für Ihre Antwort und Ihre Lösung. Kein Unterschied zwischen den eingefügten Codes. Ich habe es mit einem anderen Computer und mit einer generierten Quelldatei versucht und es funktioniert wirklich normal. Das Problem liegt möglicherweise bei den Quelldateien. – Luther

+0

@Luther Ja, wenn die Mitarbeiterdatei leer ist oder einfach nicht die aus der Nachnamen-Datei gelesenen Namen enthält (dies wäre leicht zu überprüfen). Ich hatte den Eindruck, dass Sie das erste Befehlszeilenbeispiel und das Skript auf demselben Computer ausgeführt haben. – Kusalananda

+0

Das wird fehlschlagen, wenn es John zu Johnston, Smith zu Smithers usw. und wenn es einem Mitarbeiter namens Johnston mit dem Firmennamen Johnston & Johnston usw. entspricht übereinstimmt –

2

Dies ist offensichtlich nicht getestet, da Sie nicht Abtastwerteingang gebucht haben, aber das ist die Art von Ansatz, den Sie verwenden sollten:

awk ' 
NR==FNR { if (!/#/) cnt[$1]=0; next } 
{ cnt[$WHATEVER]++ } 
END { 
    PROCINFO["sorted_in"] = "@val_num_desc" 
    for (name in cnt) { 
     print name, cnt 
     if (++c == 5) { 
      break 
     } 
    } 
} 
' /home/luther/tipical_surnames.txt /home/luther/employers.txt 

Ersetzen „UNABHÄNGIG“ mit der Feldnummer, wo Mitarbeiter Nachnamen in Arbeitgeber gespeichert sind. txt.

Die Verwendungen oben GNU awk für sorted_in, mit anderem awks würde ich nur die procinfo Leitung und die Zählung von der Ausgangsschleife und der Ausgangsrohrkopf sortieren dann entfernen, zum Beispiel:

awk ' 
NR==FNR { if (!/#/) cnt[$1]=0; next } 
{ cnt[$WHATEVER]++ } 
END { 
    for (name in cnt) { 
     print name, cnt 
    } 
} 
' /home/luther/tipical_surnames.txt /home/luther/employers.txt | sort -k2,1nr | head -5 

oder was auch immer die richtigen Sortieroptionen sind.

+0

Dank Ihrer Lösung auch, es sieht sehr nützlich aus! Aber ich weiß immer noch nicht, warum mein Code nicht funktioniert. – Luther

+0

Shell-Skripte zur Textverarbeitung sind wiederum zerbrechlich und schwer robust zu schreiben.Es gibt so viele Dinge, die das Problem verursachen könnten, es ist schwer zu erraten, welcher es tatsächlich tut. Ich sehe, dass Sie 'cut -f 1' am Ende Ihrer' Nachnamen = ... 'Zeile verwenden - das wird absolut nichts tun mit dem Dateiformat, das Sie gepostet haben - was hat es Ihrer Meinung nach getan? Die Datei, die Sie gepostet haben, hat nur 1 Feld. Warum versuchen Sie anscheinend 1 Feld auszuwählen, wenn das alles in der Datei ist? –