2010-11-24 4 views

Répondre

2

Avec awk:

awk '{print substr($2, 1, 1)}' file| 
    uniq -c| 
    awk '{print $2 ": " $1}' 

OK, pas awk. Voici avec sed:

sed s'/[^,]*, \(.\).*/\1/' file| 
    uniq -c| 
    sed 's/.*\([0-9]\)\+ \([a-zA-Z]\)\+/\2: \1/' 

OK, non sed. Voilà avec python:

import csv 
r = csv.reader(open(file_name, 'r')) 
d = {} 
for i in r: 
    d[i[1][1]] = d.get(i[1][1], 0) + 1 
for (k, v) in d.items(): 
    print "%s: %s" % (k, v) 
+0

et sans awk ,, comment cela peut-il être fait ?? –

+0

Édité, jetez un oeil. –

+0

et sans sed? :) –

1
while read -r f l r; do echo "$l"; done < inputfile | cut -c 1 | sort | uniq -c 
+0

c'est une syntaxe 'read' intéressante, je n'avais pas vu auparavant. Pouvez-vous l'expliquer s'il vous plaît? – ocodo

+1

@slomojo: C'est une lecture régulière; le -r est de désactiver les ecrits backslash '\'. Ceci (lire f, l, r) est fondamentalement 'lire premier dernier repos'. Lorsque les noms de champs apparaissent après la lecture, read interrompt l'entrée dans les champs. – frayser

0

La "dure" — aucune utilisation de awk ou sed, exactement comme demandé. Si vous n'êtes pas sûr de ce que l'une de ces commandes signifie, vous devez absolument regarder le man page pour chacun d'eux.

INTERMED=`mktemp`  # Creates a temporary file 
COUNTS_L=`mktemp`  # A second... 
COUNTS_R=`mktemp`  # A third... 

cut -d , -f 2 |   # Extracts the FamilyName field only 

tr -d '\t ' |   # Deletes spaces/tabs 

cut -c 1 |   # Keeps only the first character 
       # on each line 

tr '[:lower:]' '[:upper:]' | # Capitalizes all letters 

sort |    # Sorts the list 

uniq -c > $INTERMED  # Counts how many of each letter 
       # there are 

cut -c1-7 $INTERMED |  # Cuts out the LHS of the temp file 
tr -d ' ' > $COUNTS_R  # Must delete the padding spaces though 


cut -c9- $INTERMED > $COUNTS_L # Cut out the RHS of the temp file 

# Combines the two halves into the final output in reverse order 
paste -d ' ' /dev/null $COUNTS_R | paste -d ':' $COUNTS_L - 

rm $INTERMED $COUNTS_L $COUNTS_R # Cleans up the temp files 
+0

Vous ne devriez pas encourager ce genre de chose :) – ocodo

+0

Exactement. Cela ne me surprendrait pas si les solutions awk, sed et python s'avéraient plus rapides. C'est déjà assez grave de le faire de cette façon, deux ou trois fichiers temporaires sont facilement nécessaires. C'est pourquoi il ne faut pas se limiter à utiliser awk ou sed. – PleaseStand

+0

awk, sed, python, ruby ​​et bien sûr perl ferait tous cette tâche très facilement ... – ocodo

1

Juste Shell

#! /bin/bash 

##### Count occurance of familyname initial 

#FirstName, FamilyName, Address, PhoneNo 
exec <<EOF 
Isusara, Ali,  Someplace, 022-222 
Rat,  Fink,  Some Hole, 111-5555 
Louis, Frayser, whaterver, 123-1144 
Janet, Hayes, whoever St,  111-5555 
Mary, Holt,  Henrico VA, 222-9999 
Phillis, Hughs, Some Town, 711-5525 
Howard, Kingsley, ahahaha, 222-2222 
EOF 



while read first family rest 
do 
    init=${family:0:1} 
    [ -n "$oinit" -a $init != "$oinit" ] && { 
     echo $oinit : $count 
     count=0 
    } 
    oinit=$init 
    let count++ 
done 

echo $oinit : $count 

Courir

[email protected] ~/doc/Answers/src/SH/names $ sh names.sh 
A : 1 
F : 2 
H : 3 
K : 1 
[email protected] ~/doc/Answers/src/SH/names $ 

Pour lire un fichier, retirez le document ici, et exécutez:

chmod +x names.sh 
./names.sh <file 
+0

Certainement bash spécifique, mais wow, je ne savais pas qu'il était possible d'utiliser '&& 'et des accolades comme ça, ou la commande' let' pour incrémenter un compteur. +1 – PleaseStand

+0

Je pense que seul le "let count ++" est spécifique à Bash. KSH a "laissé compter + = 1". Drôle mais KSH sous Linux exécute ce script avec le "++" dedans; mais je ne pouvais pas trouver cela documenté pour POSIX. Le */bin/ksh * que j'ai est: "sh (AT & T Research) 1993-12-28 s +" Le '&& {}' est un ancien idiome de Bourne. – frayser

0

awk one-liner:

awk ' 
    {count[substr($2,1,1)]++} 
    END {for (init in count) print init ": " count[init]} 
' filename 
+0

Techniquement, c'est plus d'une ligne :-p – Conner

+0

meh, supprimez les nouvelles lignes si vous le souhaitez. Bash considèrera qu'un one-liner, une commande avec 2 arguments: le premier argument vient d'y avoir des caractères newline. –

0

Imprime les combien de mots commencent par chaque lettre:

pour i dans {} A..Z; fais echo -n "$ i:"; find chemin/vers/dossier -type f -exec sed "s// \ n/g" {} \; | grep^$ i | wc -c | awk '{print $ 0}'; fait

Questions connexes