Bash スクリプト計算機ループ

Bash スクリプト計算機ループ

サンプルデータ(名、姓、収入、Rax 率)を含むデータファイルがあります。いくつかの計算を行う必要がありますが、結果を表示するときにループが発生し、順番に表示されないため問題が発生しています。はい、bash を使用する必要があります。

サンプルファイル:

------------------------------------
example-file.txt:

John,Rambo,99880,2%
Elon,Musk,144000,2%
------------------------------------

テスト.bash:

#/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 ...

最後に、スクリプトを's で囲まずにファイルとして保存し、次のように呼び出すことができます。

awk -v FS=, -f awk_script file1.txt

どこかでリテラル s を使用する必要がある場合に、不便な文字列連結の必要性を排除します'。たとえば、sprintfフォーマット文字列に'フラグを含めたい場合、インライン スクリプトは次のようになります。

awk ... '... sprintf("%'"'"'.f", $3 * $4 / 100) ...' file

答え2

スクリプトにはいくつかの問題があります。まず、文字列を配列として扱っています (文字列が 1 つしかないfor foo in $bar場合は、そうする理由$barも意味もありません)。次に、ファイルを 1 回だけ読み取ればよいのに、複数回読み取っています。3 番目に、変数を引用符で囲んでいないため、ファイル名に空白文字が含まれているとスクリプトが壊れます。より良い方法は次のとおりです。

#/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

関連情報