Порахувати файли в каталозі з певним рядком на ім'я?


12

У мене є такі файли:

Codigo-0275_tdim.matches.tsv  
Codigo-0275_tdim.snps.tsv  
FloragenexTdim_haplotypes_SNp3filter17_single.tsv  
FloragenexTdim_haplotypes_SNp3filter17.tsv  
FloragenexTdim_SNP3Filter17.fas  
S134_tdim.alleles.tsv    
S134_tdim.snps.tsv  
S134_tdim.tags.tsv

Я хочу порахувати кількість файлів, на яких є ім'я слова snp(регістр). Я спробував використовувати

grep -a 'snp' | wc -l   

але потім я зрозумів, що здійснює grepпошук у файлах. Яка правильна команда для сканування назви файлів?


1
Ви намагалися шукати на цьому сайті "підрахунок файлів"?
don_crissti

Відповіді:


18

Ви маєте на увазі, що хочете шукати snpв іменах файлів ? Це був би простий глобус оболонки (wildcard), який використовується так:

ls -dq *snp* | wc -l

Пропустіть -qпрапор, якщо ваша версія lsне розпізнає його. Він обробляє назви файлів, що містять "дивні" символи (включаючи нові рядки).


Не був упевнений, чи зможу я lsотримати імена файлів із певним текстом у них. Це працювало, хоча, спасибі.
Lucia O

@LuciaO перечитав ваш коментар, це не lsвідповідність імен файлів, це оболонка. lsбачить список файлів, що відповідають шаблону; вона не бачить самого шаблону.
roaima

2
зауважте, це може не спрацювати, якщо у вас повертається занадто багато файлів.
Денніс Нолте

4

Якщо тихо стоїш у передпокої Unix & Linux і уважно слухаєш, то почуєш примарний голос, жалібно ридаючи: «А як з назви файлів, що містять нові рядки?»

ls -d *snp* | wc -l

або, що еквівалентно ,

printf "%s\n" *snp* | wc -l

виведе всі назви файлів, які містять snp, за кожним слідує новий рядок, але також включить будь-які нові рядки у файли , а потім підрахує кількість рядків у висновку. Якщо є файл, ім'я якого

                                f o o s n p \n b a r . t s v

тоді це ім'я буде записано як

foosnp
bar.tsv

що, звичайно, буде рахуватися як два рядки.

Є кілька альтернатив, які краще принаймні в деяких випадках:

printf "%s\n" * | grep -c snp

який рахує рядки, які містять snp, тому foosnp(\n)bar.tsvприклад зверху рахується лише один раз. Незначна зміна цього питання є

ls -f | grep -c snp

Вищеописані дві команди відрізняються тим, що:

  • До складу ls -fзаповіту будуть входити файли, імена яких починаються з .; цього printf … *немає, якщо не встановлено dotglobпараметр оболонки.
  • printf- вбудована оболонка; lsє зовнішньою командою. Тому, lsможливо, буде використано трохи більше ресурсів.
  • Коли оболонка обробляє a *, вона сортує імена файлів; ls -fне сортує назви файлів. Тому lsможе використовуватися трохи менше ресурсів.

Але у них є щось спільне: вони будуть давати неправильні результати за наявності імен файлів, які містять новий рядок і мають snpі до, і після нового рядка .

Ще:

filenamelist=(*snp*)
echo ${#filenamelist[@]}

Це створює змінну масиву оболонок з переліком усіх імен файлів, які містять snp, а потім повідомляє про кількість елементів у масиві. Імена файлів трактуються як рядки, а не рядки, тому вбудовані нові рядки не є проблемою. Можна припустити, що такий підхід може мати проблеми, якщо каталог величезний, оскільки список імен файлів повинен міститись в оболонці.

Ще один:

Раніше, коли ми говорили printf "%s\n" *snp*, printfкоманда повторювала (повторно використовувала) "%s\n"рядок формату один раз для кожного аргументу в розширенні *snp*. Тут ми робимо невелику зміну в цьому:

printf "%.0s\n" *snp* | wc -l

Це повторить (повторно використовувати) "%.0s\n"рядок формату один раз для кожного аргументу в розширенні *snp*. Але "%.0s"означає надрукувати перші нульові символи кожного рядка - тобто нічого. Ця printfкоманда виведе лише новий рядок (тобто порожній рядок) для кожного файлу, що містить snpйого ім'я; а потім wc -lпорахує їх. І знову ж таки, ви можете включити .файли, встановивши dotglob.


1

Анотація:

Працює для файлів з "непарними" іменами (включаючи нові рядки).

set -- *snp* ; echo "$#"                             # change positional arguments

count=$(printf 'x%.0s' *snp*); echo "${#count}"      # most shells

printf -v count 'x%.0s' *snp*; echo "${#count}"      # bash

Опис

Оскільки простий глобус буде відповідати кожному імені файлу з snpйого іменем echo *snp*, для цього випадку може бути достатньо простого , але щоб дійсно показати, що я використовую лише три файли:

$ ls -Q *snp*
"Codigo-0275_tdim.snps.tsv"  "foo * bar\tsnp baz.tsv"  "S134_tdim.snps.tsv"

Залишилося лише підрахунок файлів. Так, grep - це звичайне рішення, і так, підрахунок нових рядків wc -l- це також звичайне рішення. Зауважте, що grep -c(count) дійсно підраховує, скільки разів snpзбігається рядок, і, якщо одне ім'я файлу має більше одного snpрядка в імені, підрахунок буде неправильним.

Ми можемо зробити краще.

Одне просте рішення - встановити позиційні аргументи:

$ set -- *snp*
$ echo "$#"
3

Щоб уникнути зміни позиційних аргументів, ми можемо перетворити кожен аргумент на один символ і надрукувати довжину отриманого рядка (для більшості оболонок):

$ printf 'x%.0s' *snp*
xxx

$ count=$(printf 'x%.0s' *snp*); echo "${#count}"
3

Або, в основному, щоб уникнути низької кількості:

$ printf -v count 'x%.0s' *snp*; echo "${#count}"
3

Список файлів

Список файлів (від оригінального запитання з доданим новим рядком):

a='
Codigo-0275_tdim.matches.tsv
Codigo-0275_tdim.snps.tsv
FloragenexTdim_haplotypes_SNp3filter17_single.tsv
FloragenexTdim_haplotypes_SNp3filter17.tsv
FloragenexTdim_SNP3Filter17.fas
S134_tdim.alleles.tsv
S134_tdim.snps.tsv
S134_tdim.tags.tsv'
$ touch $a

touch $'foosnp\nbar.tsv' 

У середині буде файл з новим рядком:

f o o s n p \n b a r . t s v

І для перевірки глобального розширення:

$ touch $'foo * bar\tsnp baz.tsv'

Це додасть зірочку, яка, якщо не буде цитовано, розшириться на весь список файлів.


-1

скажімо, ви хотіли порахувати кількість HTML-файлів:

ls | grep ".html" | wc -l

тому якщо ви рахуєте випадки "snp":

ls | grep "snp" | wc -l
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.