Считать файлы в каталоге с определенной строкой на имя?


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в именах файлов ? Это был бы простой глобус оболочки (подстановочный знак), используемый следующим образом:

ls -dq *snp* | wc -l

Опустите -qфлаг, если ваша версия lsне распознает его. Он обрабатывает имена файлов, содержащие «странные» символы (включая символы новой строки).


Не был уверен, смогу ли я использовать lsдля получения имен файлов с определенным текстом в них. Это сработало, хотя, спасибо.
Люсия О

@LuciaO перечитывает ваш комментарий, дело не lsв совпадении имен файлов, а в оболочке. lsвидит список файлов, соответствующих шаблону; он не видит сам шаблон.
Ройма

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

Или, в bash, чтобы избежать подоболочки:

$ 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

И чтобы проверить расширение glob:

$ 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.