Bash-Skript-Rechnerschleife

Bash-Skript-Rechnerschleife

Ich habe eine Datendatei mit einigen Beispieldaten (Vorname, Nachname, Einkommen, Steuersatz). Ich muss einige Berechnungen durchführen, aber bei der Anzeige des Ergebnisses habe ich Probleme, da es sich um eine Schleife handelt und die Ergebnisse nicht in der richtigen Reihenfolge angezeigt werden. Ja, ich muss Bash verwenden.

Beispieldatei:

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

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

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

Ausgabe:

(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

Gewünschte Ausgabe:

John Rambo 1997
Elon Musk 2880

Wie kann ich das erreichen?

Antwort1

Da Sie es verwenden awk, um Felder aus Ihren Zeilen zu extrahieren, warum lassen Sie es nicht einfach die ganze Arbeit machen? Es sollte über ausreichende Rechenfähigkeiten verfügen und die Konvertierung Ihres Skripts in ein AWK-Skript ist möglicherweise einfacher als die Reparatur.

$ 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

Verwenden Sie das erste angegebene Argument, sprintfum das Format der gedruckten Nummer anzupassen.

Sie können auch Zeilen filtern. Angenommen, Sie sind nur an einem Einkommensbereich interessiert:

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

Es akzeptiert eine beliebige Anzahl von Dateien als Argumente (die Obergrenze hängt von Ihrer Systemkonfiguration ab; wenn Sie viele davon haben, verwenden Sie find ... -exec awk ...):

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

Schließlich können Sie das Skript als Datei ohne das einschließende '„s“ speichern und es wie folgt aufrufen:

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

Dadurch entfällt die Notwendigkeit umständlicher Zeichenfolgenverkettungen, falls Sie 'irgendwo wörtliche s verwenden müssen. Wenn Sie beispielsweise möchten, dass die sprintfFormatzeichenfolge das 'Flag enthält, würde das Inline-Skript folgendermaßen aussehen:

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

Antwort2

Ihr Skript weist mehrere Probleme auf. Erstens behandeln Sie Zeichenfolgen als Arrays (das ist weder sinnvoll noch sinnvoll, for foo in $barwenn es $barsich nur um eine Zeichenfolge handelt). Zweitens lesen Sie die Datei mehrere Male, obwohl Sie sie nur einmal lesen müssen. Drittens setzen Sie Ihre Variablen nicht in Anführungszeichen, was bedeutet, dass das Skript abbricht, wenn die Dateinamen Leerzeichen enthalten können. Hier ist eine bessere Möglichkeit:

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

Sie können dies mit der/den Datei(en) als Argumente ausführen:

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

verwandte Informationen