bash echo liczba wierszy pliku podana w zmiennej bash bez nazwy pliku

79

Mam następujące trzy konstrukcje w skrypcie bash:

NUMOFLINES=$(wc -l $JAVA_TAGS_FILE)
echo $NUMOFLINES" lines"

echo $(wc -l $JAVA_TAGS_FILE)" lines"

echo "$(wc -l $JAVA_TAGS_FILE) lines"

Oba generują identyczne dane wyjściowe po uruchomieniu skryptu:

121711 /home/slash/.java_base.tag lines
121711 /home/slash/.java_base.tag lines
121711 /home/slash/.java_base.tag lines

Oznacza to, że wyświetlana jest również nazwa pliku (czego nie chcę). Dlaczego te rysiki zawodzą i jak powinienem wypisać czysty:

121711 lines

?

Marcus Junius Brutus
źródło
Możliwy duplikat uzyskania tylko liczby całkowitej z wc w bash
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Odpowiedzi:

157

Przykład z wykorzystaniem własnych danych

Możesz uniknąć osadzania nazwy pliku w zmiennej NUMOFLINES , używając przekierowania z JAVA_TAGS_FILE zamiast przekazywania nazwy pliku jako argumentu do wc . Na przykład:

NUMOFLINES=$(wc -l < "$JAVA_TAGS_FILE")

Objaśnienie: Użyj potoków lub przekierowania, aby uniknąć nazw plików w wyjściu

Narzędzie wc nie wypisze nazwy pliku w swoim wyjściu, jeśli dane wejściowe są pobierane z potoku lub operatora przekierowania. Rozważ te różne przykłady:

# wc shows filename when the file is an argument
$ wc -l /etc/passwd
41 /etc/passwd

# filename is ignored when piped in on standard input
$ cat /etc/passwd | wc -l
41

# unusual redirection, but wc still ignores the filename
$ < /etc/passwd wc -l
41

# typical redirection, taking standard input from a file
$ wc -l < /etc/passwd
41

Jak widać, jedyną sytuacją , w której wc wypisze nazwę pliku, jest przekazanie jej jako argumentu, a nie danych na standardowym wejściu. W niektórych przypadkach możesz chcieć wydrukować nazwę pliku, więc warto wiedzieć, kiedy zostanie wyświetlona.

Todd A. Jacobs
źródło
1
uważaj, to podejście nie obejmie ostatniej linii, jeśli ostatnia linia nie kończy się znakiem końca linii. Zobacz moją poprawkę poniżej.
trwa
15

wc nie można uzyskać nazwy pliku, jeśli jej nie podasz.

wc -l < "$JAVA_TAGS_FILE"
Ignacio Vazquez-Abrams
źródło
2
Więc nie rób tego. Po prostu przekaż plik na wcstdin, jak pokazano w odpowiedzi. Więc cat "$JAVA_TAGS_FILE" | wc -lalbo, równoważnie wc -l < "$JAVA_TAGS_FILE". W ten sposób wcpobiera tylko surowe dane, a nie nazwę pliku.
Witiko,
12

Możesz także użyć awk:

awk 'END {print NR,"lines"}' filename

Lub

awk 'END {print NR}' filename

Javier López
źródło
5

(zastosuj na Macu i prawdopodobnie innych Uniksach)

W rzeczywistości istnieje problem z podejściem wc: nie liczy ostatniej linii, jeśli nie kończy się symbolem końca linii.

Użyj tego zamiast tego

nbLines=$(cat -n file.txt | tail -n 1 | cut -f1 | xargs)

lub nawet lepiej (dzięki gniourf_gniourf):

nblines=$(grep -c '' file.txt)

Uwaga: działa również podejście chilicuil w awk.

molwa
źródło
2
Bardzo zawiła metoda! Może będziesz chciał nblines=$(grep -c '' file)zamiast tego (co jest kanonicznym sposobem liczenia niekompletnych wierszy w tym przypadku). Zauważ jednak, że zgodnie z POSIX liczysz niekompletne wiersze (a nie wiersze ). W rzeczywistości masz do czynienia z plikiem binarnym, a nie plikiem tekstowym .
gniourf_gniourf
@gniourf_gniourf Dzięki, nie wiedziałem o tym, działa świetnie i jest jeszcze bardziej zwięzłe.
trwa
to może lepsze rozwiązanienblines=$(($(cat "file.txt" | wc -l) + 1))
Andrey Izman
3

To bardzo proste:

NUMOFLINES=$(cat $JAVA_TAGS_FILE | wc -l )

lub

NUMOFLINES=$(wc -l $JAVA_TAGS_FILE | awk '{print $1}')
Slava Semushin
źródło
Pierwsza to bezużyteczne wykorzystanie kota.
kap
@kap Nie, tylko wygląda tak. Jeśli się pozbędziesz cat, będziesz miał drugi przykład wtedy, ponieważ wc -lzwraca 2 kolumny, gdy jest używany tylko z plikiem.
Slava Semushin
-3

Zwykle używam funkcji „back tick” w bash

export NUM_LINES=`wc -l filename`

Zauważ, że „tick” to „back tick”, np. „Nie jest zwykłym pojedynczym cudzysłowem

Russ Hore
źródło
5
To po prostu inna notacja i nie rozwiązuje problemu, że nazwa pliku jest częścią wyniku.
Izzy