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

?


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.


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"

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


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.


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}')

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


5
To po prostu inna notacja i nie rozwiązuje problemu, że nazwa pliku jest częścią wyniku.
Izzy
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.