Jeśli stoisz cicho na korytarzach Uniksa i Linuksa i słuchasz uważnie, usłyszysz upiorny głos, żałośnie lamentujący: „A co z nazwami plików, które zawierają nowe linie?”
ls -d *snp* | wc -l
lub, równoważnie ,
printf "%s\n" *snp* | wc -l
wypisze wszystkie nazwy plików, które zawierają snp, po których następuje nowa linia,
ale także uwzględni wszystkie nowe linie w nazwach plików , a następnie policzy liczbę linii w danych wyjściowych. Jeśli istnieje plik o nazwie
f o o
s n p \n
b a r
. t s v
wtedy ta nazwa zostanie zapisana jako
foosnp
bar.tsv
które oczywiście będą liczone jako dwie linie.
Istnieje kilka alternatyw, które działają lepiej przynajmniej w niektórych przypadkach:
printf "%s\n" * | grep -c snp
która liczy linie, które zawierają snp, więc foosnp(\n)bar.tsvprzykład z powyższego liczy się tylko raz. Jest to niewielka zmiana
ls -f | grep -c snp
Dwa powyższe polecenia różnią się tym, że:
ls -fBędzie zawierać pliki, których nazwy zaczynają się .; printf … *nie, chyba że dotglobopcja powłoki jest ustawiona.
printfjest wbudowaną powłoką; lsto polecenie zewnętrzne. Dlatego lsmogą zużywać nieco więcej zasobów.
- Kiedy powłoka przetwarza a
*, sortuje nazwy plików;
ls -fnie sortuje nazw plików. Dlatego lsmogą zużywać nieco mniej zasobów.
Ale mają coś wspólnego: oba dadzą złe wyniki w obecności nazw plików zawierających znak nowej linii, które mają snpzarówno przed, jak i po nowej linii .
Inne:
filenamelist=(*snp*)
echo ${#filenamelist[@]}
Spowoduje to utworzenie zmiennej tablicowej powłoki zawierającej wszystkie nazwy plików, które zawierają snp, a następnie zgłasza liczbę elementów w tablicy. Nazwy plików są traktowane jako ciągi znaków, a nie wiersze, więc osadzone znaki nowej linii nie stanowią problemu. Można sobie wyobrazić, że takie podejście może mieć problem, jeśli katalog jest ogromny, ponieważ lista nazw plików musi być przechowywana w pamięci powłoki.
Jeszcze inny:
Wcześniej, kiedy powiedzieliśmy printf "%s\n" *snp*, printfpolecenie powtórzyło (ponownie wykorzystało) "%s\n"ciąg formatu raz dla każdego argumentu w rozszerzeniu *snp*. Tutaj dokonujemy niewielkiej zmiany w tym:
printf "%.0s\n" *snp* | wc -l
Spowoduje to powtórzenie (ponowne użycie) ciągu "%.0s\n"formatu raz dla każdego argumentu w rozszerzeniu *snp*. Ale "%.0s"oznacza wydrukowanie pierwszych zerowych znaków każdego łańcucha - tzn. Nic. To printfpolecenie wyświetli tylko nowy wiersz (tj. Pusty wiersz) dla każdego pliku, który zawiera snpw nazwie; i wtedy wc -lje policzą. I znowu możesz dołączyć .pliki, ustawiając dotglob.