Contém arquivos no diretório com uma string específica no nome?

6

Eu tenho os seguintes arquivos:

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

Eu quero contar o número de arquivos que têm a palavra snp (diferencia maiúsculas de minúsculas) em seu nome. Eu tentei usar

grep -a 'snp' | wc -l   

mas percebi que grep procura nos arquivos. Qual é o comando correto para digitalizar os nomes dos arquivos?

    
por Lucia O 13.05.2015 / 00:16

4 respostas

13

Você quer dizer que deseja procurar snp no arquivo nomes ? Isso seria um simples shell glob (curinga), usado assim:

ls -dq *snp* | wc -l

Omita o sinal -q se a sua versão de ls não o reconhecer. Ele lida com nomes de arquivos contendo caracteres "estranhos" (incluindo novas linhas).

    
por 13.05.2015 / 00:22
4

Se você ficar quieto nos corredores do Unix e Linux e ouça atentamente, você vai ouvir uma voz fantasmagórica, lamentavelmente lamentando, “E os nomes de arquivos que contêm novas linhas?”

ls -d *snp* | wc -l

ou, de forma equivalente ,

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

produzirá todos os nomes de arquivos que contêm snp , cada um seguido por uma nova linha, mas também incluindo quaisquer novas linhas nos nomes de arquivos , e conte o número de linhas na saída. Se houver um arquivo cujo nome é

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

então esse nome será escrito como

foosnp
bar.tsv

que, claro, será contado como duas linhas.

Existem algumas alternativas que melhoram em pelo menos alguns casos:

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

que conta as linhas que contêm snp , Portanto, o exemplo foosnp(\n)bar.tsv acima conta apenas uma vez. Uma ligeira variação disso é

ls -f | grep -c snp

Os dois comandos acima são diferentes:

  • O ls -f incluirá arquivos cujos nomes começam com . ; o printf … * não, a menos que a opção dotglob shell esteja definida.
  • printf é um shell embutido; ls é um comando externo. Portanto, o ls pode usar um pouco mais de recursos.
  • Quando o shell processa um * , ele classifica os nomes dos arquivos; ls -f não classifica os nomes dos arquivos. Portanto, o ls pode usar um pouco menos recursos.

Mas eles têm algo em comum: ambos darão resultados errados na presença de nomes de arquivos que contêm nova linha e têm snp antes e depois da nova linha .

Outro:

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

Isso cria uma variável de matriz de shell listando todos os nomes de arquivos que contém snp e, em seguida, informa o número de elementos na matriz. Os nomes dos arquivos são tratados como seqüências de caracteres, não linhas, novas linhas embutidas não são um problema. É concebível que esta abordagem possa ter um problema se o diretório é enorme, porque a lista de nomes de arquivos deve ser mantida na memória do shell.

Ainda outro:

Anteriormente, quando dissemos printf "%s\n" *snp* , o comando printf repetido (reutilizado) a string de formato "%s\n" uma vez para cada argumento na expansão de *snp* . Aqui, fazemos uma pequena mudança nisso:

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

Isso repetirá (reutilizar) a string de formato "%.0s\n" uma vez para cada argumento na expansão de *snp* . Mas "%.0s" significa imprimir os primeiros zero caracteres de cada string - ou seja, nada. Este comando printf gerará apenas uma nova linha (ou seja, uma linha em branco) para cada arquivo que contenha snp em seu nome; e então wc -l os contará. E, novamente, você pode incluir os arquivos . definindo dotglob .

    
por 13.05.2015 / 06:57
0

digamos que você queira contar o número de arquivos html:

ls | grep ".html" | wc -l

então se você está contando ocorrências de "snp":

ls | grep "snp" | wc -l
    
por 29.08.2018 / 22:21
0

Resumo:

Funciona para arquivos com nomes "ímpares" (incluindo novas linhas).

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

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

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

Descrição

Como um simples glob corresponderá a cada nome de arquivo com snp em seu nome, um simples echo *snp* poderia ser suficiente para este caso, mas realmente mostrar que há apenas três arquivos correspondentes que eu usarei:

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

O único problema restante é contar os arquivos. Sim, o grep é uma solução usual, e sim contar novas linhas com wc -l também é uma solução usual. Observe que grep -c (contagem) realmente conta quantas vezes uma snp string é correspondida e, se um nome de arquivo tiver mais de uma snp string no nome, a contagem estará incorreta.

Podemos fazer melhor.

Uma solução simples é definir os argumentos posicionais:

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

Para evitar alterar os argumentos posicionais, podemos transformar cada argumento em um caractere e imprimir o tamanho da string resultante (para a maioria dos shells):

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

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

Ou, no bash, para evitar um subnível:

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

Lista de arquivos

Lista de arquivos (da pergunta original com um com uma nova linha adicionada):

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' 

Isso terá um arquivo com uma nova linha no meio:

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

E para testar a expansão glob:

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

Isso adicionará um asterisco que, se não for indicado, será expandido para toda a lista de arquivos.

    
por 30.08.2018 / 02:18

Tags