Loop de calculadora de script Bash

Loop de calculadora de script Bash

Eu tenho um arquivo de dados com alguns dados de amostra (Nome, Sobrenome, Renda, Taxa Rax). Preciso fazer alguns cálculos, mas na hora de exibir o resultado estou tendo problemas pois é um loop e não está exibindo na ordem. Sim, devo usar o bash.

Arquivo de exemplo:

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

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

teste.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

Saída:

(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

Saída desejada:

John Rambo 1997
Elon Musk 2880

Como posso conseguir isso?

Responder1

Já que você está usando awkpara extrair campos de suas linhas, por que não deixa ele fazer todo o trabalho? Ele deve ter recursos aritméticos suficientes e converter seu script em um script AWK pode ser mais fácil do que corrigi-lo.

$ 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

Use o primeiro argumento fornecido sprintfpara ajustar o formato do número impresso.

Você também pode filtrar linhas. Por exemplo, supondo que você esteja interessado apenas em uma faixa de renda:

$ awk -v FS=, '
  80000 < $3 && $3 < 150000 {
    print $1,$2,sprintf("%i",$3 * $4 / 100)
  }'

Ele aceita um número arbitrário de arquivos como argumentos (o limite superior depende da configuração do seu sistema; se você tiver muitos deles, use find ... -exec awk ...):

awk -v FS=, '...' file1.txt file2.txt ...

Finalmente, você pode salvar o script como um arquivo, sem os 's anexos, e invocá-lo como:

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

eliminando a necessidade de concatenações de strings inconvenientes caso você precisasse usar literais 'em algum lugar. Por exemplo, se você quisesse que a sprintfstring de formato incluísse o 'sinalizador, o script embutido se tornaria:

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

Responder2

Seu script tem vários problemas. Primeiro, você está tratando strings como arrays (não há razão ou sentido em fazer for foo in $barquando $barhá apenas uma string). Segundo, você está lendo o arquivo várias vezes, quando tudo o que precisa fazer é lê-lo uma vez. Terceiro, você não está citando suas variáveis, o que significa que o script será interrompido se os nomes dos arquivos puderem conter espaços em branco. Aqui está uma maneira melhor:

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

Você pode executar isso com os arquivos como argumentos:

$ foo.sh file
John Rambo 1,997
Elon Musk 2,880

informação relacionada