名前に特定の文字列があるディレクトリ内のファイルをカウントしますか?


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特定のテキストが含まれるファイル名を取得するために使用できるかどうか確信が持てませんでした。それでもうまくいきました、ありがとう。
Lucia O

@LuciaOがコメントを再読み込みしますls。ファイル名と一致しているのではなく、シェルです。lsパターンに一致するファイルのリストを表示します。パターン自体見えませ
roaima

2
返されるファイルが多すぎる場合、これは機能しない可能性があることに注意してください。
Dennis Nolte

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

もちろん、これは2行として数えられます。

少なくともいくつかのケースでより良いいくつかの選択肢があります:

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

これは、を含む行をカウントするsnpため、foosnp(\n)bar.tsv上記の例では1回しかカウントされません。これのわずかなバリエーションは

ls -f | grep -c snp

上記の2つのコマンドは、次の点で異なります。

  • ls -fで始まる名前のファイルが含まれます.。シェルオプションが設定されてprintf … *いない限り、これは行われませんdotglob
  • printf組み込みシェルです。ls外部コマンドです。したがって、はls少し多くのリソースを使用する可能性があります。
  • シェルはaを処理するときに、*ファイル名をソートします。 ls -fファイル名を並べ替えません。したがって、はls少しだけリソースを使用する可能性があります。

しかし、彼らは共通で何かを持っている:彼らは両方の改行が含まれているファイル名の存在下で間違った結果が得られますし、持っているsnp改行の前と後の両方を

別の:

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

これにより、を含むすべてのファイル名をリストするシェル配列変数が作成さsnpれ、配列の要素数が報告されます。ファイル名は行ではなく文字列として扱われるため、埋め込まれた改行は問題になりません。ファイル名のリストはシェルメモリに保持する必要があるため、ディレクトリが巨大な場合、このアプローチには問題が発生する可能性があると考えられます。

さらに別の:

以前、私たちが言ったprintf "%s\n" *snp*とき、printfコマンド"%s\n"はの展開の各引数に対してフォーマット文字列を1回繰り返しました(再利用しました)*snp*。ここでは、少し変更を加えます。

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

これは"%.0s\n"、の展開の引数ごとにフォーマット文字列を1回繰り返します(再利用します)*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*するため、この場合は単純で十分ですが、実際には3つのファイルしか一致しないことを示すために使用します。

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

残っている唯一の問題は、ファイルを数えることです。はい、grepは通常のソリューションであり、はいで改行を数えることwc -lも通常のソリューションです。grep -c(count)は、snp文字列が一致した回数を実際に数えることに注意してください。1つのファイル名に複数のsnp文字列が含まれている場合、その数は正しくありません。

私たちはもっと上手にできる。

簡単な解決策の1つは、位置引数を設定することです。

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

位置引数を変更しないようにするには、各引数を1文字に変換し、結果の文字列の長さを出力します(ほとんどのシェルの場合)。

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

中央に改行が1つあるファイルが作成されます。

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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.