次のファイルがあります。
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
snp
ファイル内で検索するという意味です。名前?これは、次のように使用される単純なシェルグローブ(ワイルドカード)です。
ls -dq *snp* | wc -l
-q
ls
あなたのバージョンがこのフラグを認識しない場合は、このフラグを無視してください。 「奇妙な」文字(改行文字を含む)を含むファイル名を処理します。
答え2
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
の例では一度だけ計算します。これに対するわずかに異なるアプローチは次のとおりです。
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
フォーマット文字列を1回繰り返し(再利用)します。ここでは小さな変化を与えます:"%s\n"
*snp*
printf "%.0s\n" *snp* | wc -l
これにより、"%.0s\n"
.extensionの各パラメータに対してフォーマット文字列が1回繰り返し(再利用)されます*snp*
。ただし、"%.0s"
各文字列の最初のゼロ文字を印刷することを意味します。つまり、何も印刷しません。このコマンドは、printf
名前に含まれる各ファイルに対して1つの改行文字(つまり空行)のみを出力してからsnp
計算wc -l
されます。そして.
設定によってこれらのファイルを含めることができますdotglob
。
答え3
抽象的な:
「奇妙な」名前(改行を含む)を持つファイルに対して機能します。
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
単純なglobは名前のすべてのファイル名と一致するので、echo *snp*
この場合は単純なファイルで十分ですが、実際には3つのファイルのみが一致するかどうかを示すために次のようにします。
$ ls -Q *snp*
"Codigo-0275_tdim.snps.tsv" "foo * bar\tsnp baz.tsv" "S134_tdim.snps.tsv"
残りの唯一の問題は、ファイル数を数えることです。はい、grepは一般的な解決策であり、はい、新しい行を数えるのがwc -l
一般的な解決策です。 (count)はgrep -c
実際に文字列が一致する回数を計算し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
そしてグローバル拡張をテストします。
$ touch $'foo * bar\tsnp baz.tsv'
アスタリスクが追加されて引用符を使用しない場合は、ファイル全体のリストに展開されます。
答え4
htmlファイルの数を数えたいとしましょう。
ls | grep ".html" | wc -l
したがって、「snp」の発生回数を計算するには、次の手順を実行します。
ls | grep "snp" | wc -l