Bash 스크립트 계산기 루프

Bash 스크립트 계산기 루프

일부 샘플 데이터(이름, 성, 소득, 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 ...

마지막으로 스크립트를 파일로 저장하고(닫는 's 없이) 다음과 같이 호출할 수 있습니다.

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

관련 정보