SCALEFACTOR
基本的にを探そうとします10000/(sum of 4th column in a file)
。出力から小数点をどのように取得しますか?助けてくれてありがとう。
#!/bin/bash
FILES=/path/to/files/*;
for f in ${FILES}
do
echo $f
COLTOTAL="$(awk '{sum += $4} END {print sum}' $f)"
echo "total: ${COLTOTAL}"
# SCALEFACTOR=`expr 10^5 / $COLTOTAL`
B=10000
SCALEFACTOR=$((B / ${COLTOTAL}))
SCALINGFACTOR=$(echo "100000 / $COLTOTAL" | bc -l
# echo "scale=5; ${SCALEFACTOR}" | bc
echo ${SCALEFACTOR}
awk '{print($1"\t"$2"\t"$3"\t"$4 * ${SCALINGFACTOR})}' $f > $f"_normalized.txt"
done
答え1
for
ファイルにスペースが含まれていると、ループの実装方法が中断されます。for f in /path/to/files/*
ループが理解するように拡張が行われるため、変数なしでうまく機能しますfor
。
一般に、新しいプロセスを開始するとリソースが消費されるため、sumインスタンスを1つだけ持つことがより良く、@jw013が指摘したように、sumは浮動小数点演算を実行できないため、シェルのawk
外部で分割する必要があります。sh
bash
各行で作業するにはファイルの終わりを知る必要があるため、2つのオプションがあります。つまり、各ファイルを読んだり、2番目の読取りのために各行を保存したり、各ファイルを2回読んだりします。大容量ファイルをメモリに保存することは問題になる可能性があるため、2番目のオプションを選択しました。
for f in /path/to/files/*; do
echo "$f"
awk '
NR == FNR {
sum += $4;
next;
}
FNR == 1 {
print "total: " sum;
SCALEFACTOR = 10000 / sum;
print SCALEFACTOR;
}
{
printf("%s\t%s\t%s\t%f\n", $1, $2, $3, $4 * SCALEFACTOR);
}' "$f" "$f"
NR == FNR
これは、合計レコード(行)番号が現在のファイルのレコード番号と同じであることを意味します。つまり、現在のファイルが最初のファイルにあり、現在のジョブが合計を決定することを意味します。 next
他の条項が実行されるのを防ぎます。そうではなく、2番目にファイルの最初の行を読み取ると、呼び出し間で行ったawk
操作が実行されます。 2番目の読み取りの各行に4つの項目を印刷し、4番目の項目を指定したサイズでサイズ変更します。
4番目の項目に標準文字列形式を使用できます。たとえば、bc
コメントの5番目のレベルは%f
次のように変更されます。%.5f
答え2
(echo "scale=5"; echo "100000 / $COLTOTAL") | bc -l