
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, sprintf
um 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 sprintf
Formatzeichenfolge 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 $bar
wenn es $bar
sich 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