質問
ファイルでいっぱいのgitリポジトリがあり、ほとんどはテキストです。
あるか知りたいです。
n
次に終わるファイルのコード行.py
m
次に終わるファイルのコード行.md
o
次に終わるファイルのコード行.yaml
p
ファイルのコード行拡張子なし- など
メモ:
- 再帰的に実行したいです。フォルダ内を確認してください。
.git
トップレベルフォルダのディレクトリを除外したいです。- バイナリファイルを無視することは可能です(拡張子のないテキストファイルと拡張子のないバイナリファイルの一部があります)。
- 大文字と小文字を区別したいです。
.csv
グループ.CSV
- 空行(または空行のみ)を無視したいです。
- 私と同じファイルがある場合は、
myfile.yaml.j2
グループ.j2
または.yaml.j2
。
答え1
この試み:
find ./ -not -path "./.git/*" -type f -exec wc -l {} + |
awk '{print tolower($0)}' |
sed -e '$ d' |
sed -e "s#/.*/##g" |
sed -e "s/\./ \./g" |
awk '
{ if ( NF <= 2 ) { count["none"] += $1 } else { count[$NF] += $1 } }
{ next }
END { for (group in count) printf("%d%s%s\n", count[group], OFS, group) }
' |
sort -n
分割:
find ./
このディレクトリからオブジェクトを繰り返し検索します。-not -path "./.git/*"
入らないようにする.git
-type f
ディレクトリの代わりにファイル-exec wc -l {} +
各ファイルに対して単語数ユーティリティ(wc
)を実行します。これには空行が含まれているため、質問のすべての要件を満たしているわけではありません。awk '{print tolower($0)}'
小文字になるsed -e '$ d'
すべてのファイルの行の合計である最後の行を削除します。sed -e "s#/.*/##g"
たとえば、削除されたファイルへのパスは、拡張子ではなく拡張子がa/something.egg/blah
ないと計算する必要があります。.egg/blah
sed -e "s/\./ \./g"
ファイル拡張子が独自の単語になるように検索/.
置換する.
awk '{ if ( NF <= 2 ) { count["none"] += $1 } else { count[$NF] += $1 } } { next } END { for (group in count) printf("%d%s%s\n", count[group], OFS, group) }'
これは大きな問題です。awk
強力ですが、非常に鋭くはありません。count
辞書ですif (NF <= 2)
「単語」が3つ未満の場合、拡張子はありません。count["none"] += $1
辞書の要素を増分します。キーは文字列リテラルですnone
。最初の単語であるファイルの行数を追加して増分します。$1
count[$NF] += $1
辞書に要素を追加します。キーは$NF
(行の最後の単語)、拡張子は$1
(行の最初の単語)はファイルの行数です。{ next }
すべての行に対して繰り返しfor (group in count)
ループfor
、インラインprintf(...)
number extension
たとえば、出力文字列の形式を;で指定します123 .abc
(で終わるファイルに123行がある場合.abc
)。
sort -n
結果を昇順に並べ替えます。-n
文字列ではなく数字でソートすることを意味します。
答え2
私が正しく理解し、テストが良い場合は、次のことをお勧めします(隠しディレクトリとファイルをスキップしたいとし、そうでない場合はお知らせください)。
shopt -s globstar
declare -A arr
for f in test/**; do
# if a directory, skip
[[ -d "$f" ]] && continue
lines=0
# strip the extension
ext="${f##*.}"
# convert it to lowercase
ext="${ext,,}"
# if no dot in the name, extension is "empty"
[[ ! $(basename "$f") =~ \. ]] && ext="empty"
# count the lines
lines=$(wc -l "$f"| cut -d' ' -f1)
# if lines equals to 0, skip
[[ $lines -eq 0 ]] && continue
# append the number of line to the array
lines=$(( "${arr[$ext]}"+$lines ))
arr[$ext]=$lines
done
# loop over the array
for n in ${!arr[@]}; do
echo "files $n: total lines ${arr[$n]}"
done
出力(例ファイルから):
files yaml: total lines 3
files md: total lines 3
files empty: total lines 4
files csv: total lines 6
files py: total lines 5
答え3
わかりやすいように関数別に分けました。
#!/bin/bash
# For the next two functions, we will use "-print0", which will print out \0 instead of \n.
# This will help prevent whitespace problems when piping the filenames into xargs.
find_extension()
{
find "$1" -type f -name "*.$2" -print0 2>/dev/null
}
find_no_extension()
{
find "$1" -type f -regex '^.*/[^.]+$' -print0 2>/dev/null
}
concat_files()
{
xargs -0 cat
}
delete_empty_lines()
{
sed -E '/^[[:space:]]*$/d'
}
line_count_of_files()
{
concat_files | delete_empty_lines | wc -l
}
print_usage()
{
echo "Usage: $0 [EXTENSION]... [SEARCH_DIRECTORY]";
}
NUMBER_OF_EXTENSIONS=$(($# - 1))
SEARCH_DIR="${*: -1}"
if [ $# -lt 2 ];
then
echo "Not enough parameters.";
print_usage;
exit 1;
fi
if ! [ -d "$SEARCH_DIR" ];
then
echo "$SEARCH_DIR does not exist, or is not a directory."
print_usage;
exit 1;
fi
for EXTENSION in "${@:1:$NUMBER_OF_EXTENSIONS}";
do
printf ".$EXTENSION: %s\n" $(find_extension "$SEARCH_DIR" "$EXTENSION" | line_count_of_files)
done
printf "No extension: %s\n" $(find_no_extension "$SEARCH_DIR" | line_count_of_files)
これは、検索するファイル拡張子を指定できる一般的なスクリプトに近いです。ただし、常に拡張子のないファイルを検索します。
ファイルに保存して実行権限を付与したら、PATHに入れる必要があります。名前をcount_lines.shとして指定するとします。次のように呼び出すことができますcount_lines.sh py md yaml ~/Code
。これにより、ディレクトリ内で~/Code
、およびで終わるファイルと拡張子がまったくないファイルを検索します。検索する拡張子を好きなだけ選択できます。少なくとも1つがあることを確認してください。.py
.md
.yaml