Contare le occorrenze di un carattere in una stringa utilizzando Bash


123

Ho bisogno di contare il numero di occorrenze di un carattere in una stringa usando Bash.

Nel seguente esempio, quando il carattere è (per esempio) t, è echos il corretto numero di occorrenze di ta var, ma quando il carattere è virgola o virgola, esso stampa a zero:

var = "text,text,text,text" 
num = `expr match $var [,]`
echo "$num"

Risposte:


118

Userei il seguente awkcomando:

string="text,text,text,text"
char=","
awk -F"${char}" '{print NF-1}' <<< "${string}"

Sto dividendo la stringa per $chare stampo il numero di campi risultanti meno 1.

Se la tua shell non supporta l' <<<operatore, usa echo:

echo "${string}" | awk -F"${char}" '{print NF-1}'

5
@HattrickNZ Quindi usa:$(grep -o "$needle" < filename | wc -l)
hek2mgl

13
@Amir Cosa ti aspetti?
hek2mgl

3
Puoi saltare il wc -l, basta usare grep -c, funziona sia su bsd grep che su linux grep.
andsens

8
@andsens restituirà grep -csolo il numero di righe corrispondenti. Non conta più corrispondenze per riga.
hek2mgl

1
Voglio contare '$' in una stringa, come posso fare l'escape '$' dalla stringa principale?
masT

117

puoi ad esempio rimuovere tutti gli altri caratteri e contare ciò che rimane, come:

var="text,text,text,text"
res="${var//[^,]}"
echo "$res"
echo "${#res}"

stamperà

,,,
3

o

tr -dc ',' <<<"$var" | awk '{ print length; }'

o

tr -dc ',' <<<"$var" | wc -c    #works, but i don't like wc.. ;)

o

awk -F, '{print NF-1}' <<<"$var"

o

grep -o ',' <<<"$var" | grep -c .

o

perl -nle 'print s/,//g' <<<"$var"

1
qualche altro trucco qui comey="${x//[^s|S]}"; echo "${#y}"
Aquarius Power

4
usa il primo, dovresti sempre evitare di ricorrere alla generazione di un altro processo per funzionare in questo modo, può influire gravemente sulle prestazioni quando si utilizza con grandi cicli di iterazione. Di norma, l'esecuzione di processi esterni dovrebbe essere l'ultima risorsa quando si utilizzano operazioni di iterazione o ripetizione.
osirisgothra

Perché non ti piace wc? Gioca a golf!
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
@CiroSantilli 六四 事件 法轮功 包 卓 轩 perché ad esempioecho -n some line | wc -l
jm666

Il blocco di codice 4 è il migliore secondo me. Dobbiamo rendere più facile raggiungere:tr -dc ',' <<<"$var" | wc -c
bgStack15

68

Puoi farlo combinando tre wccomandi. Ad esempio, per contare enella stringa referee

echo "referee" | tr -cd 'e' | wc -c

produzione

4

Spiegazioni: Command tr -cd 'e'rimuove tutti i caratteri tranne "e" e Commandwc -c conta i caratteri rimanenti.

Anche più righe di input sono utili per questa soluzione, come il comando cat mytext.txt | tr -cd 'e' | wc -cpuò contare enel file mytext.txt, anche se il file può contenere molte righe.


3
La tua soluzione sembra essere la più pulita e facile da ricordare, grazie!
jirislav

Questo è fantastico. Grazie!
Kodie Grantham

Lo adoro, perché odio awk!
franzisk

3

Basandosi sulle ottime risposte e commenti di tutti, questa è la versione più breve e dolce:

grep -o "$needle" <<< "$haystack" | wc -l


2

awk funziona bene se ce l'ha il tuo server

var="text,text,text,text" 
num=$(echo "${var}" | awk -F, '{print NF-1}')
echo "${num}"

Proprio come una nota: awk -F,cerca un file ,. Puoi fare quanto segue:awk -F"${your_char}"
Emixam23

1

Suggerirei quanto segue:

var="any given string"
N=${#var}
G=${var//g/}
G=${#G}
(( G = N - G ))
echo "$G"

Nessuna chiamata a nessun altro programma


1

controlla anche questo, ad esempio vogliamo contare t

echo "test" | awk -v RS='t' 'END{print NR-1}'

o in python

python -c 'print "this is for test".count("t")'

o ancora meglio, possiamo rendere dinamico il nostro script con awk

echo 'test' | awk '{for (i=1 ; i<=NF ; i++) array[$i]++ } END{ for (char in array) print char,array[char]}' FS=""

in questo caso l'output è come questo:

e 1
s 1
t 2
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.