
Tengo un archivo de datos con algunos datos de muestra (nombre, apellido, ingresos, tasa Rax). Necesito hacer algunos cálculos, pero al mostrar el resultado, tengo problemas porque es un bucle y no se muestra en orden. Sí, debo usar bash.
Archivo de ejemplo:
------------------------------------
example-file.txt:
John,Rambo,99880,2%
Elon,Musk,144000,2%
------------------------------------
prueba.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
Producción:
(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
Salida deseada:
John Rambo 1997
Elon Musk 2880
¿Cómo puedo lograr eso?
Respuesta1
Ya que estás utilizando awk
para extraer campos de tus líneas, ¿por qué no dejas que haga todo el trabajo? Debería tener suficientes capacidades aritméticas y convertir su script en un script AWK puede ser más fácil que arreglarlo.
$ 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
Utilice el primer argumento dado a sprintf
para ajustar el formato del número impreso.
También puedes filtrar líneas. Por ejemplo, suponiendo que solo le interesa un rango de ingresos:
$ awk -v FS=, '
80000 < $3 && $3 < 150000 {
print $1,$2,sprintf("%i",$3 * $4 / 100)
}'
Acepta una cantidad arbitraria de archivos como argumentos (el límite superior depende de la configuración de su sistema; si tiene muchos, use find ... -exec awk ...
):
awk -v FS=, '...' file1.txt file2.txt ...
Finalmente, puede guardar el script como un archivo, sin la '
s adjunta, e invocarlo como:
awk -v FS=, -f awk_script file1.txt
eliminando la necesidad de concatenaciones de cadenas inconvenientes en caso de que necesite usar literales '
en alguna parte. Por ejemplo, si quisiera que la sprintf
cadena de formato incluyera la '
bandera, el script en línea sería:
awk ... '... sprintf("%'"'"'.f", $3 * $4 / 100) ...' file
Respuesta2
Su guión tiene varios problemas. En primer lugar, está tratando las cadenas como matrices (no tiene sentido hacerlo for foo in $bar
cuando $bar
es solo una cadena). En segundo lugar, estás leyendo el archivo varias veces cuando todo lo que necesitas hacer es leerlo una vez. En tercer lugar, no está citando sus variables, lo que significa que el script se interrumpirá si los nombres de los archivos pueden contener espacios en blanco. Aquí hay una mejor manera:
#/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
Puede ejecutar esto con los archivos como argumentos:
$ foo.sh file
John Rambo 1,997
Elon Musk 2,880