Para procesar un CSV en Bash no hace falta ningún programa extra: cut saca columnas, awk suma, filtra y reordena, y sort ordena por la columna que quieras. Aquí tienes cada operación con su resultado real, el límite de la aritmética de Bash y cómo tratar el caso que rompe las soluciones rápidas: los campos con comas entre comillas.
También te puede interesar
Los ejemplos usan este archivo, ventas.csv, con una cabecera y cuatro columnas:
terminal$ cat ventas.csv fecha,producto,cantidad,precio 2026-10-01,Teclado,2,349.90 2026-10-01,Ratón,5,199.00 2026-10-02,Monitor,1,3899.00 2026-10-03,Teclado,1,349.90 2026-10-03,Cable USB-C,10,89.50 2026-10-04,Ratón,2,199.00
Una columna con cut
terminal$ cut -d, -f2 ventas.csv
producto
Teclado
Ratón
Monitor
Teclado
Cable USB-C
Ratón
$ tail -n +2 ventas.csv | cut -d, -f2 | sort | uniq -c | sort -rn
2 Teclado
2 Ratón
1 Monitor
1 Cable USB-Ccut -d, -f2 separa cada línea por las comas y se queda con el segundo campo. En la segunda orden, tail -n +2 se salta la cabecera (empieza en la línea 2), y la cadena sort | uniq -c | sort -rn cuenta cuántas veces aparece cada producto y las ordena de más a menos: es una de las combinaciones más útiles de la terminal.
Sumar, filtrar y reordenar con awk
Para todo lo que sea calcular, awk es la herramienta. Con -F, separa por comas, y cada campo está en $1, $2, etc.; NR es el número de línea:
terminal$ awk -F, 'NR > 1 { total += $3 * $4 } END { printf "Total vendido: %.2f\n", total }' ventas.csv
Total vendido: 7236.70
$ awk -F, 'NR > 1 { suma[$2] += $3 * $4 } END { for (p in suma) printf "%-12s %9.2f\n", p, suma[p] }' ventas.csv | sort
Cable USB-C 895.00
Monitor 3899.00
Ratón 1393.00
Teclado 1049.70
$ awk -F, 'NR == 1 || $3 >= 2' ventas.csv
fecha,producto,cantidad,precio
2026-10-01,Teclado,2,349.90
2026-10-01,Ratón,5,199.00
2026-10-03,Cable USB-C,10,89.50
2026-10-04,Ratón,2,199.00
$ awk -F, -v OFS=, '{ print $2, $1, $4 }' ventas.csv
producto,fecha,precio
Teclado,2026-10-01,349.90
Ratón,2026-10-01,199.00
Monitor,2026-10-02,3899.00
Teclado,2026-10-03,349.90
Cable USB-C,2026-10-03,89.50
Ratón,2026-10-04,199.00Línea por línea: el total de cantidad por precio; lo vendido por producto, en un array que se recorre al final (for (p in suma) no garantiza ningún orden, por eso el sort); las filas con dos unidades o más, conservando la cabecera; y las columnas en otro orden, con OFS=, para que la salida siga siendo CSV.
Ordenar por una columna
terminal$ { head -n 1 ventas.csv; tail -n +2 ventas.csv | sort -t, -k4,4nr; }
fecha,producto,cantidad,precio
2026-10-02,Monitor,1,3899.00
2026-10-01,Teclado,2,349.90
2026-10-03,Teclado,1,349.90
2026-10-01,Ratón,5,199.00
2026-10-04,Ratón,2,199.00
2026-10-03,Cable USB-C,10,89.50-t, indica el separador, -k4,4 ordena por la cuarta columna y solo por ella, n compara como números y r invierte el orden. La cabecera se imprime aparte para que no se mezcle con los datos.
Bash no sabe de decimales
Leer el CSV con un bucle while read funciona para recorrer las filas, pero la aritmética de Bash es solo de enteros:
#!/usr/bin/env bash
{
read -r # se salta la cabecera
while IFS=, read -r fecha producto cantidad precio; do
importe=$(awk -v c="$cantidad" -v p="$precio" 'BEGIN { printf "%.2f", c * p }')
printf '%s %-12ls %9s\n' "$fecha" "$producto" "$importe"
done
} < ventas.csv
echo "Y con la aritmética de Bash:"
echo $(( 2 * 349.90 ))salida con error2026-10-01 Teclado 699.80 2026-10-01 Ratón 995.00 2026-10-02 Monitor 3899.00 2026-10-03 Teclado 349.90 2026-10-03 Cable USB-C 895.00 2026-10-04 Ratón 398.00 Y con la aritmética de Bash: ./decimales.sh: line 11: 2 * 349.90 : arithmetic syntax error: invalid arithmetic operator (error token is ".90 ")
ShellCheck también lo avisa, antes de ejecutar nada:
shellcheckIn decimales.sh line 11:
echo $(( 2 * 349.90 ))
^----^ SC2079 (error): (( )) doesn't support decimals. Use bc or awk.
For more information:
https://www.shellcheck.net/wiki/SC2079 -- (( )) doesn't support decimals. U...El %-12ls rellena hasta 12 caracteres; con %-12s, el printf de Bash cuenta bytes y la fila de «Ratón» saldría con un espacio de menos. El { read -r; while …; done; } < ventas.csv abre el archivo una sola vez: el primer read consume la cabecera y el bucle sigue desde la segunda línea. Para multiplicar precios hay que salir a awk o a bc. Y si la tarea es sobre todo de cálculo, mejor hacerla entera en awk, como en la sección anterior, que es mucho más rápido que llamarlo en cada vuelta.
El problema de verdad: comas dentro de comillas
En CSV, un campo que contiene comas va entre comillas, y unas comillas dentro de un campo se escriben dobles. Este archivo es perfectamente válido:
terminal$ cat clientes.csv nombre,ciudad,saldo "Pérez, Ana",Monterrey,1500 Luis Gómez,"Guadalajara, Jal.",230 "María ""Mary"" Ruiz",Puebla,980 $ cut -d, -f2 clientes.csv ciudad Ana" "Guadalajara Puebla
cut no sabe nada de comillas, y la segunda columna sale mal en dos de las tres filas. GNU awk (gawk) tiene una variable, FPAT, que describe cómo es un campo en lugar de cómo es el separador: «o texto sin comas, o algo entre comillas»:
#!/usr/bin/env bash
gawk -v FPAT='([^,]*)|("([^"]|"")*")' '
function limpiar(c) {
if (c ~ /^"/) {
c = substr(c, 2, length(c) - 2)
gsub(/""/, "\"", c)
}
return c
}
NR > 1 { printf "%-18s %-18s %6s\n", limpiar($1), limpiar($2), $3 }
' clientes.csvsalidaPérez, Ana Monterrey 1500 Luis Gómez Guadalajara, Jal. 230 María "Mary" Ruiz Puebla 980
La función limpiar quita las comillas de los extremos y convierte las comillas dobles en simples. Esto cubre casi todos los CSV del mundo real, salvo uno: los campos con saltos de línea dentro de las comillas, que awk partiría en dos registros. Para esos, usa un analizador de verdad: mlr (Miller), csvkit o unas líneas de Python con su módulo csv.
Escribir CSV válido
Al escribir hay que hacer lo contrario: si un campo contiene comas, comillas o saltos de línea, se rodea de comillas y sus comillas se duplican.
#!/usr/bin/env bash
# Escribe un campo CSV: si lleva comas, comillas o saltos de línea, lo encierra entre comillas y duplica las comillas.
campo_csv() {
local c=$1
if [[ $c == *[,\"$'\n']* ]]; then
c=${c//\"/\"\"}
printf '"%s"' "$c"
else
printf '%s' "$c"
fi
}
# Escribe una fila: los campos separados por comas y un salto de línea al final.
fila_csv() {
local primero=1 c
for c in "$@"; do
if (( ! primero )); then
printf ','
fi
campo_csv "$c"
primero=0
done
printf '\n'
}
{
fila_csv nombre ciudad saldo
fila_csv "Pérez, Ana" Monterrey 1500
fila_csv "Luis Gómez" "Guadalajara, Jal." 230
fila_csv 'María "Mary" Ruiz' Puebla 980
} > nuevos.csv
cat nuevos.csvsalidanombre,ciudad,saldo "Pérez, Ana",Monterrey,1500 Luis Gómez,"Guadalajara, Jal.",230 "María ""Mary"" Ruiz",Puebla,980
El patrón *[,\"$'\n']* comprueba si el campo contiene una coma, unas comillas o un salto de línea ($'\n' es la forma de escribir un salto de línea en Bash), y ${c//\"/\"\"} duplica cada comilla. El archivo resultante se lee bien con el gawk de antes y con cualquier hoja de cálculo.
- TareaHerramientaOjo
- Una columna, CSV simple
cut -d, -fNno entiende comillas - Sumar, filtrar, reordenar
awk -F,salta la cabecera conNR > 1 - Ordenar por columna
sort -t, -kN,Nnimprime la cabecera aparte - Campos con comas entre comillas
gawk -v FPAT=…solo GNU awk; en macOS,brew install gawk - Saltos de línea dentro de camposMiller, csvkit o Pythonlas herramientas de líneas no sirven
Todos los scripts de esta página se ejecutaron con Bash 5.3 en Ubuntu 26.04, en un contenedor limpio sin acceso a la red, y pasaron ShellCheck 0.11 sin avisos antes de publicarla; las salidas están copiadas de esa ejecución.