フォルダー内の.js
ファイルの行の合計を考え出そうとしています。私はこれをbashで使用しています:
sum=0 && find . | grep ".js" | while read -r f; do wc -l $f | awk '{print $1;}'; done;
awk
内に$sum += $1
を配置しても機能しません。これをどうやって行うのですか?
PS:私はこれを使用してはるかに簡単に達成できることを知っています
find . -name '*.js' | xargs wc -l
私はまだ上記の解決策を求めています。
この簡単で超高速なソリューションを試してください:
find . -type f -name "*.js" -exec cat {} + | wc -l
以前にwc
を使用していくつかの解決策を試しましたが、それらには問題があります。ファイル名の改行や遅い。
lastpipe
Shellオプションを有効にしない限り、bashはパイプラインの各コマンドを個別のサブシェルで実行します
# bash requires job control to be disabled for lastpipe setting
set +m
shopt -s lastpipe
declare -i sum=0
find . -name '*.js' -print0 | while IFS= read -d '' -r name; do
(( sum += $(wc -l < "$name") )) # redirect the file into wc for easier output
done
echo $sum
プロセスの置換 は、このサブシェルの問題を処理するのに便利です。
declare -i sum=0
while IFS= read -d '' -r name; do
(( sum += $(wc -l < "$name") )) # redirect the file into wc for easier output
done < <(
find . -name '*.js' -print0
)
echo $sum
ただし、これによりプログラムフローが読みにくくなります。
awk
に加算して結果を表示しますか?
awk '{sum +=$1} END {print sum}'
トリックを行う必要があります。
私のライブラリでは、bashスクリプトを次のようにしています。
$ find . -type f -name '*.bash' \
| while read -r f ; do wc -l "$f" ; done \
| awk '{sum +=$1} END {print sum}'
結果を取得します522
shopt -s globstar; # valid for bash
set -- ./**/*".js"; cat "$@" | wc -l # for files under `./` directory
shopt -s globstar; # valid for bash
set -- ./**/*".js" # for files under `./` directory
wc -l "$@" | awk '{sum+=$1} END {print sum-=$1}' # calculate the sum in awk
しかし、wc -l
が合計を最終行に出力する場合、なぜ合計を再計算するのでしょうか。 :
wc -l "$@" | tail -n 1
改善される可能性のある要素がいくつかあります。
| awk '{print $1;}'
の代わりにwc -l <"$f"
を実行する場合、最初のフィールドのみを選択するwc -l $f
の部分は必要ありません。単純なリダイレクト(<
)により、wcは標準入力でファイルを受信し、印刷するファイル名がなくなります。これにより、スクリプトが次のように削減されます。
見つける。 | grep ".js" |読み取り中-r f; do wc -l <"$ f";できた
Findが選択を行う場合、grepを呼び出す必要はありません。
見つける。 -name '* .js' |読み取り中-r f; do wc -l <"$ f";できた
読み取りは、ファイル名から先頭と末尾の空白を削除します。
そして実際には、findは各ファイルに対してコマンドを実行できます(暗黙のループ)。
見つける。 -name '* .js' -exec sh -c 'wc -l <"$ 1"' foo '{}' \;
また、ファイルごとに1つではなく、wc
を1回グローバルに呼び出すことも可能です。
見つける。 -name '* .js' -exec sh -c 'cat "$ @" | wc -l 'foo' {} '+
ただし、スペース、タブ、改行、またはグロブ文字(*、?、[)の問題なしに各ファイル名を処理するためにシェルを再度呼び出す必要があることは、特別な検索が必要ない場合は、シェルで直接解決できることを示しています。リンクの解決。
set -- *.js; cat "$@" | wc -l # for the present directory
または
shopt -s globstar; # valid for bash
set -- ./**/*".js"; cat "$@" | wc -l # for files under `./` directory
タイトルの質問はあなたのパイプのこの部分に関するものです:
while read -r f; do wc -l $f …
上記のように、ファイルのリストが引数リスト($@
)(または配列内にある場合もあります)にあるとすると、最初のフィールドとして行数を含むファイルのリストが出力されます。
$ printf '%s\n' "$@" | while read -r f; do wc -l "$f"; done
12 filea.js
21 fileb.js
この時点で、awkを使用して新しいパイプを追加し、最初のフィールドを選択できます。
$ printf '%s\n' "$@" | while read -r f; do wc -l "$f"; done | awk '{print $1}'
12
21
ただし、+
を追加して、すべてを1行で出力することもできます。
$ printf '%s\n' "$@" |
> while read -r f; do wc -l "$f"; done |
> awk '{printf( "%s+",$1)}'
12+21+
そして、末尾に0
を追加し、bcですべてを合計します。
$ printf '%s\n' "$@" |
> while read -r f; do wc -l "$f"; done |
> awk '{printf("%s+",$1)}END{print 0}' |
> bc
33
ただし、すでに述べたように、wc -l <"$f"`` and you can convert the newlines to
+ , then add a
0`を使用したファイル名の出力を回避し、bcに計算を行わせることができます。
$ printf '%s\n' "$@" |
while read -r f; do wc -l <"$f"; done |
{ tr '\n' '+'; echo 0; } |
bc
33
またはawkに合計を計算させる:
$ printf '%s\n' "$@" |
while read -r f; do wc -l <"$f"; done |
awk '{sum+=$1} END {print sum}'
33
これを行う別のbash方法を次に示します。
sum=0 && while IFS= read -r -d '' f; do let sum+=$(sed -n "\$=" "${f}"); done < <(find . -name '*.js' -print0 2>/dev/random) && echo "$sum"
find ... -print0 -- prints with null terminated
IFS= -- deset IFS
read -r -d '' -- -r do not allow backslash escapes, -d '' set delimiter to NULL
let sum+=(..) -- add up sum of sed $= "$f", $: last line, =: line #