いくつかのサンプルデータ(名前、姓、所得、Raxの割合)を含むデータファイルがあります。計算を少しする必要がありますが、結果を表示するとループになり、順番に表示されないため問題が発生します。はい、bashを使用する必要があります。
サンプルファイル:
------------------------------------
example-file.txt:
John,Rambo,99880,2%
Elon,Musk,144000,2%
------------------------------------
テスト。
#/bin/bash
FILE=example-file.txt
for file in $FILE;
do
# Get income
INCOME=$(cat $file | awk -F, '{print $3}');
FIRSTNAME=$(cat $file | awk -F, '{print $1}');
LASTNAME=$(cat $file | awk -F, '{print $2}');
# Get tax rate
RATE=$(cat $file | awk -F, '{print $4}' | sed 's/%//');
for foo in $INCOME
do
if [ "$foo" -ge 80000 ] && [ "$foo" -lt 150000 ];
then
for faa in $foo
do
NETINCOME=$(printf "%'.f\n" $(echo "(($INCOME * $RATE / 100))" | bc))
done
fi
echo "${FIRSTNAME} ${LASTNAME} ${NETINCOME}"
done
done
出力:
(standard_in) 2: syntax error
(standard_in) 3: syntax error
John
Elon Rambo
Musk 288,000
(standard_in) 2: syntax error
(standard_in) 3: syntax error
John
Elon Rambo
Musk 288,000
希望の出力:
John Rambo 1997
Elon Musk 2880
どうすればいいですか?
答え1
行からフィールド抽出を使用しているので、awk
すべての操作を実行するようにしておくのはどうですか?適切な算術機能が必要で、スクリプトを変更するよりもAWKスクリプトに変換する方が簡単です。
$ cat example-file.txt
John,Rambo,99880,2%
Elon,Musk,144000,2%
$ awk -v FS=, '{ print $1,$2,sprintf("%i", $3 * $4 / 100) }' example-file.txt
John Rambo 1997
Elon Musk 2880
指定された最初の引数を使用して、sprintf
印刷された数字の形式を調整します。
行をフィルタリングすることもできます。たとえば、収入の範囲にのみ関心があるとします。
$ awk -v FS=, '
80000 < $3 && $3 < 150000 {
print $1,$2,sprintf("%i",$3 * $4 / 100)
}'
引数はファイル数に関係なく許可されます(上限はシステム構成によって異なります。ファイルが多い場合はそれを使用してくださいfind ... -exec awk ...
)。
awk -v FS=, '...' file1.txt file2.txt ...
最後に、スクリプトをファイルとして保存し(閉じる'
ことなく)、次のように呼び出すことができます。
awk -v FS=, -f awk_script file1.txt
どこかでリテラルを使用する必要がある場合は、不便な文字列連結を実行する必要はありません'
。たとえば、sprintf
フォーマット文字列にフラグを含めたい場合、'
インラインスクリプトは次のようになります。
awk ... '... sprintf("%'"'"'.f", $3 * $4 / 100) ...' file
答え2
スクリプトにはいくつかの問題があります。まず、文字列を配列として扱います(単にfor foo in $bar
文字列である場合、それを行う理由や意味はありません)。$bar
第二に、ファイルを一度だけ読む必要がありますが、ファイルを複数回読み取ることです。第三に、変数を引用しません。つまり、ファイル名にスペースを含めることができる場合、スクリプトは中断されます。より良いアプローチは次のとおりです。
#/bin/bash
## take a list of file names as an argument so you can
## work on multiple files.
for file in "$@";
do
## get the values
while read firstName lastName income rate; do
rate=${rate//%}
if [[ "$income" -ge 80000 && "$income" -lt 150000 ]]; then
netIncome=$(printf "%'.f\n" $(echo "($income * $rate) / 100" | bc))
## You didn't specify what should happen if the income isn't in the
## target range, so I am assuming you want it to be the $income unchanged.
else
netIncome=$income
fi
echo "$firstName $lastName $netIncome"
done < <(awk -F, '{print $1,$2,$3,$4}' "$file")
done
ファイルを引数として使用して実行できます。
$ foo.sh file
John Rambo 1,997
Elon Musk 2,880