2013-02-27 15 views
23

Chcę policzyć liczbę słów z ciągu za pomocą powłoki.Jak liczyć liczbę słów z ciągu za pomocą powłoki

Załóżmy, że ciąg jest:

input="Count from this String" 

Tutaj separatorem jest przestrzeń ' ' i oczekiwany wynik to 4. Nie może być też końcowe spacje w ciągu wejściowego jak "Count from this String ".

Jeśli w łańcuchu występuje spacja końcowa, powinna ona wytworzyć to samo wyjście, czyli 4. Jak to zrobić?

+1

Dlaczego downvote pytanie? Czy to znaczy, że jeśli ktoś czegoś nie wie i inni to wiedzą, mogą po prostu zgodzić się. –

Odpowiedz

30
echo "$input" | wc -w 

Użyj wc -w, aby policzyć liczbę słów.

Albo jak za sugestią dogbane, tym echo można pozbył także:

wc -w <<< "$input" 

Jeśli < < < nie jest obsługiwany przez powłokę można wypróbować ten wariant:

wc -w << END_OF_INPUT 
$input 
END_OF_INPUT 
+6

To jest [Useless Use of Echo] (http://fahdshariff.blogspot.com/2012/12/useless-use-of-echo.html).Zamiast tego użyj 'wc -w <<<" $ input "'. – dogbane

+0

Dziękuję Tuxdude i Dogbane za odpowiedzi. Jeśli użyję wc -w <<< "$ input" otrzymuję komunikat o błędzie: ** błąd składni: got <&, oczekiwanie na słowo **. Jakieś pomysły? –

+0

Którą powłokę uruchamiasz? – Tuxdude

27

Nie potrzebujesz zewnętrznego polecenia, takiego jak wc, ponieważ możesz to zrobić w czystej wersji bash, która jest bardziej wydajna.

przekonwertować ciąg do tablicy, a następnie policzyć elementy w tablicy:

$ input="Count from this String " 
$ words=($input) 
$ echo ${#words[@]} 
4 

Alternatywnie wykorzystać set ustawienie parametrów pozycyjnych, a następnie policzyć:

$ input="Count from this String " 
$ set -- $input 
$ echo $# 
4 
+3

Drugi wariant ma efekt uboczny, który nadpisze parametry pozycyjne, takie jak wszystkie otrzymane z wiersza poleceń lub parametry przekazane do funkcji (jeśli te linie są w funkcji). Więc upewnij się, że nie polegasz na 1 $, 2 $ itd. Po użyciu zestawu - $ input – Tuxdude

+0

@Tuxdude To było bardzo ważne. Dzięki –

+0

@dogbane Drugie rozwiązanie sugerowane przez ciebie działa dobrze dla mnie, ale jak zauważył Tuxdude, nie mogę zastąpić istniejących parametrów nowymi, ponieważ będą one łamały bieżący przepływ. Próbowałem zaimplementować pierwsze rozwiązanie, ale niestety dostaję błąd: ** błąd składniowy: dostałem (, spodziewając się Newline ** –

5

to zrobić w czysty bash unikający efektów ubocznych, zrób to w sub-powłoce:

$ input="Count from this string " 
$ echo $(IFS=' '; set -f; set -- $input; echo $#) 
4 

Współpracuje z innych separatorów, a także:

$ input="dog,cat,snake,billy goat,horse" 
$ echo $(IFS=,; set -f; set -- $input; echo $#) 
5 
$ echo $(IFS=' '; set -f; set -- $input; echo $#) 
2 

Uwaga stosowanie „ustaw -f”, który wyłącza bash filename expansion w podpowłoce, więc jeśli rozmówca chce ekspansji powinno być wykonane wcześniej (Hat Tip @ mkelement0).

+2

Dobrze zrobiłem, sugeruję przedkładanie 'set -f;' do każdego polecenia 'set' (uwaga: musi to być _separate_ command), aby (tymczasowo) wyłączyć rozszerzenie nazwy ścieżki, co zapewnia, że ​​tokeny wejściowe, takie jak '*', nie zostały przypadkowo rozwinięte. – mklement0

3

Spróbuj następujące jedną wkładkę:

echo $(c() { echo $#; }; c $input) 

Zasadniczo określa c() funkcję i przechodzi $input jako argumentu, a następnie powraca $# liczbę elementów argumentu oddzielone odstępami. Aby zmienić ogranicznik, możesz zmienić IFS (zmienną specjalną).

3
echo "$input" | awk '{print NF}' 
+0

Podoba mi się to, że z 'NF-x' gdzie x jest dowolną liczbą, możesz z dala od pól, które nie mają być policzone. – PdC

0

Ja po prostu dostroić się z perl jedną wkładką (unikanie 'bezużytecznego wykorzystania echo'):

perl -lane 'print scalar(@F)' <<< $input 
Powiązane problemy