grep, sed y awk en Linux: ejemplos de procesamiento de texto en la terminal
grep busca líneas por patrón (grep -rn error /var/log), sed modifica el texto en un flujo o dentro de un archivo (sed -i 's/viejo/nuevo/g' archivo) y awk trabaja con columnas y hace cálculos (awk '{print $1}' access.log). Combinados en un pipeline sustituyen a un script: grep filtra las líneas, sed corrige el texto y awk extrae campos y agrupa datos.
grep, sed y awk son tres utilidades clásicas de Linux para procesar texto. grep encuentra líneas que coinciden con un patrón, sed reemplaza y elimina texto en un flujo sin abrir un editor, y awk divide cada línea en columnas y sabe contar. A continuación encontrará ejemplos de grep, sed y awk que de verdad se necesitan al analizar logs, archivos de configuración y la salida de comandos, además de errores habituales.
Cuándo usar cada herramienta
Las tres leen el texto línea a línea y escriben el resultado en la salida estándar, por eso se encadenan fácilmente con |. La diferencia está en la tarea que resuelve mejor cada una.
| Tarea | Herramienta | Ejemplo |
|---|---|---|
| Encontrar líneas con un texto | grep | grep ERROR app.log |
| Reemplazar texto | sed | sed 's/http:/https:/g' archivo |
| Eliminar o mostrar líneas por número | sed | sed -n '10,20p' archivo |
| Extraer una columna | awk | awk '{print $1}' access.log |
| Sumar, promediar o agrupar | awk | awk '{s+=$10} END {print s}' |
Una regla sencilla: si solo necesita filtrar, use grep; si necesita cambiar el texto, use sed; si el texto tiene columnas o necesita aritmética, use awk.
grep: búsqueda de líneas por patrón
Ejemplos básicos de grep
# Líneas con la palabra error en un archivo
grep error /var/log/syslog
# Sin distinguir mayúsculas: Error, ERROR, error
grep -i error app.log
# Con números de línea
grep -n "Connection refused" app.log
# Recursivamente en un directorio, con nombres de archivo
grep -rn "DB_HOST" /etc/myapp/
# Solo los nombres de archivo donde hay coincidencias
grep -rl "TODO" src/
# Invertir: todo, EXCEPTO comentarios y líneas vacías
grep -v -e '^#' -e '^$' /etc/ssh/sshd_config
# Contar las líneas que coinciden
grep -c " 500 " access.log
El flag -w busca la palabra completa: grep -w log no encontrará login. El flag -F desactiva las expresiones regulares y busca la cadena literalmente, lo cual es útil cuando el patrón contiene puntos, paréntesis o asteriscos.
Contexto alrededor de la línea encontrada
Un error en el log rara vez se entiende con una sola línea; hace falta la traza o la petición que lo provocó. Para eso existen los flags de contexto:
# 3 líneas después de la coincidencia (After)
grep -A 3 "Traceback" app.log
# 2 líneas antes (Before)
grep -B 2 "OOM" /var/log/kern.log
# 5 líneas a cada lado (Context)
grep -C 5 "segfault" /var/log/syslog
grep separa los grupos de coincidencias con una línea --, así que la salida se lee con facilidad.
grep y las expresiones regulares
Por defecto grep entiende las expresiones regulares básicas (BRE). Con el flag -E se activan las extendidas (ERE), donde +, ?, | y los paréntesis funcionan sin barras invertidas.
| Construcción | Significado | Ejemplo |
|---|---|---|
^ | inicio de línea | grep '^root' /etc/passwd |
$ | final de línea | grep 'bash$' /etc/passwd |
. | cualquier carácter | grep 'h.t' |
* | 0 o más repeticiones | grep 'ab*c' |
+ (ERE) | 1 o más | grep -E '[0-9]+' |
| (ERE) | o | grep -E 'error|warn' |
[...] | un carácter de un conjunto | grep '[Ee]rror' |
# Líneas con errores o advertencias
grep -E "ERROR|WARN" app.log
# Solo direcciones IP del log, una por línea (-o imprime solo la coincidencia)
grep -oE '([0-9]{1,3}\.){3}[0-9]{1,3}' access.log
grep -P: extraer un valor entre partes conocidas
GNU grep tiene el flag -P, que usa expresiones regulares al estilo Perl. Con él están disponibles \K («olvidar todo lo coincidente hasta este punto») y la búsqueda anticipada, lo que permite extraer solo el valor:
$ echo 'user_id=4821 status=ok' | grep -oP 'user_id=\K[0-9]+'
4821
$ grep -oP '"version":\s*"\K[^"]+' package.json
2.4.1
El flag -P no está en todas las versiones de grep (por ejemplo, grep de BSD en macOS no lo tiene), así que en scripts portables es mejor usar sed o awk.
grep -q en condiciones de scripts
grep -q no imprime nada y solo devuelve el código de salida: 0 si encontró la coincidencia, 1 si no. Así la comprobación se escribe directamente en un if:
if grep -q "^PermitRootLogin no" /etc/ssh/sshd_config; then
echo "el acceso de root por SSH está desactivado"
fi
Es más corto que guardar la salida en una variable y comprobar si está vacía, y grep se detiene en la primera coincidencia.
sed: reemplazo y eliminación de texto
Reemplazo: el comando s
El comando principal de sed es s/patrón/reemplazo/indicadores. Sin el indicador g se reemplaza solo la primera coincidencia de cada línea.
# Mostrar el texto con el reemplazo (el archivo no cambia)
sed 's/foo/bar/' file.txt
# Reemplazar todas las apariciones de cada línea
sed 's/foo/bar/g' file.txt
# Sin distinguir mayúsculas (GNU sed)
sed 's/error/ERROR/gI' app.log
# Otro separador, si el texto contiene barras
sed 's|/var/www|/srv/www|g' nginx.conf
sed -i: reemplazo directamente en el archivo
El flag -i escribe el resultado de nuevo en el archivo. Para no perder el original, indique un sufijo de copia de seguridad:
# Crea config.ini.bak y modifica config.ini
sed -i.bak 's/^debug=true/debug=false/' config.ini
# Reemplazo en todos los .conf de un directorio
find /etc/myapp -name "*.conf" -exec sed -i 's/old-host/new-host/g' {} +
Antes de una edición masiva, ejecute el comando sin -i y revise la salida. En macOS (sed de BSD) -i necesita un argumento obligatorio: sed -i '' 's/a/b/' archivo.
Trabajar con líneas por número y por patrón
# Mostrar las líneas 10–20 (-n desactiva la impresión automática, p = imprimir)
sed -n '10,20p' file.txt
# Eliminar la línea 5
sed '5d' file.txt
# Eliminar la última línea
sed '$d' file.txt
# Eliminar líneas vacías y comentarios
sed -e '/^$/d' -e '/^#/d' nginx.conf
# Reemplazar solo en las líneas que contienen "listen"
sed '/listen/s/80/8080/' nginx.conf
# Insertar una línea después de una coincidencia (GNU sed)
sed '/^\[mysqld\]/a max_connections = 500' my.cnf
Referencias inversas y &
La parte del patrón entre paréntesis puede reutilizarse en el reemplazo con \1, \2, y el símbolo & representa todo el texto encontrado.
# Intercambiar nombre y apellido (ERE con -E)
$ echo "García Pedro" | sed -E 's/(\S+) (\S+)/\2 \1/'
Pedro García
# Poner entre corchetes todos los números
$ echo "port 8080, timeout 30" | sed -E 's/[0-9]+/[&]/g'
port [8080], timeout [30]
# Convertir la fecha 2026-10-14 en 14.10.2026
$ echo 2026-10-14 | sed -E 's/([0-9]{4})-([0-9]{2})-([0-9]{2})/\3.\2.\1/'
14.10.2026
awk: columnas, condiciones y cálculos
Mostrar la columna necesaria
awk divide cada línea en campos por espacios y tabulaciones: $1 es el primer campo, $2 el segundo, $NF el último y $0 toda la línea.
# Direcciones IP del log de nginx (primera columna)
awk '{print $1}' /var/log/nginx/access.log
# Nombre de usuario y shell de /etc/passwd (separador: dos puntos)
awk -F: '{print $1, $7}' /etc/passwd
# Última columna
df -h | awk '{print $NF}'
# Separador propio en la salida
awk -F: -v OFS=';' '{print $1, $3}' /etc/passwd
Condiciones: mostrar solo las líneas necesarias
Antes del bloque entre llaves se puede poner una condición: awk ejecutará la acción solo en las líneas que la cumplan.
# Usuarios con UID de 1000 en adelante (usuarios normales, no del sistema)
awk -F: '$3 >= 1000 {print $1}' /etc/passwd
# Peticiones con código de respuesta 500 o superior (campo 9 en formato combined)
awk '$9 >= 500' access.log
# Líneas en las que la columna 6 coincide con una expresión regular
awk '$6 ~ /POST/' access.log
# Archivos de más de 100 MB en la salida de ls -l
ls -l | awk '$5 > 100*1024*1024 {print $9}'
BEGIN, END y NR: awk como un pequeño programa
El bloque BEGIN se ejecuta antes de leer la primera línea, y END, después de la última. NR guarda el número de la línea actual, y dentro de END contiene el total.
# Suma de tamaños de respuesta (campo 10) en megabytes
awk '{sum += $10} END {printf "%.1f MB\n", sum/1024/1024}' access.log
# Tiempo medio de respuesta a partir de la última columna
awk '{s += $NF} END {if (NR) print s/NR}' timings.log
# Omitir la cabecera de un CSV
awk -F, 'NR > 1 {print $2}' users.csv
# Conteo de peticiones por IP: array asociativo
awk '{count[$1]++} END {for (ip in count) print count[ip], ip}' access.log | sort -rn | head
El último ejemplo es un clásico del análisis de logs: el array count, con la IP como clave, sustituye al par sort | uniq -c y se amplía fácilmente, por ejemplo, para sumar el tráfico de cada dirección.
Pipelines: grep, sed y awk juntos
La verdadera potencia está en la combinación. Cada herramienta hace su parte y | pasa el resultado a la siguiente.
Las 10 IP con errores 5xx
grep ' 50[0-9] ' /var/log/nginx/access.log \
| awk '{print $1}' \
| sort | uniq -c | sort -rn | head -10
412 203.0.113.45
118 198.51.100.7
36 192.0.2.19
Aquí grep descarta de forma aproximada las líneas, awk extrae el campo y sort | uniq -c cuenta las repeticiones. También se puede escribir todo con un solo awk: awk '$9 ~ /^5/ {c[$1]++} END {for (i in c) print c[i], i}' access.log | sort -rn | head. Es más preciso, porque comprueba exactamente la columna del código de respuesta.
Qué URL se abren con más frecuencia
awk '{print $7}' access.log | sed 's/?.*//' | sort | uniq -c | sort -rn | head
sed aquí elimina la cadena de consulta, para que /search?q=a y /search?q=b se cuenten como una misma página.
Valores de un archivo de configuración sin comentarios
grep -v '^\s*#' /etc/myapp/app.env | grep '=' | awk -F= '{print $1}'
Errores de una hora concreta
grep '14/Oct/2026:03:' access.log | awk '$9 >= 500 {print $4, $7, $9}'
Errores habituales
- Comillas dobles en lugar de simples con awk. En
awk "{print $1}"el shell sustituye su propia variable$1antes de ejecutar awk. Escriba el programa de awk y las expresiones de sed entre comillas simples. - Olvidar
gen sed. Sin él se reemplaza solo la primera coincidencia de la línea; las demás permanecen. sed -isin comprobar. Una expresión regular equivocada estropeará el archivo sin avisar. Pruebe primero sin-io use-i.bak.+y|no funcionan en grep. Es sintaxis extendida: necesitagrep -E(osed -E).- El punto en el patrón.
grep 192.168.1.1también encontrará192x168y1z1, porque el punto significa «cualquier carácter». Usegrep -Fo escápelo como\.. - Espacios en las columnas. Si un campo puede contener espacios (CSV, rutas), indique el separador de forma explícita:
awk -F,oawk -F'\t'. - cat innecesario.
cat archivo | grep xfunciona, perogrep x archivoes más corto y no crea un proceso adicional.
Con qué reemplazar grep, sed y awk
Para JSON estas utilidades resultan incómodas: la estructura se analiza mejor con jq (jq '.items[] | select(.status=="active") | .name'), y YAML, con yq. Para búsquedas recursivas rápidas en proyectos grandes se usa a menudo ripgrep (comando rg), que por defecto respeta .gitignore. Si prefiere la sintaxis de Perl, perl -pe 's/a/b/g' y perl -lane 'print $F[0]' reemplazan sed y awk en una sola línea. Pero grep, sed y awk están prácticamente en cualquier servidor sin necesidad de instalar nada, por eso conviene conocerlos antes que nada.
Resumen
grep busca líneas, sed las modifica y awk trabaja con columnas y cuenta. Recuerde el conjunto básico: grep -rniE y -A/-B/-C, sed 's/.../.../g' con -i.bak y -n 'Np', y awk -F con $1, $NF, condiciones y el bloque END. Con estas piezas se construye casi cualquier análisis de logs. Estos ejemplos de grep, sed y awk, junto con find, jq y curl, se practican en la lección del curso de Linux sobre el procesamiento de texto en la terminal.
Preguntas frecuentes
¿En qué se diferencia grep de egrep?
egrep es un alias obsoleto de grep -E (expresiones regulares extendidas). Las versiones actuales de GNU grep muestran un aviso al llamar a egrep, así que escriba grep -E.
¿Cómo buscar un texto en todos los archivos de un directorio en Linux?
Use grep -rn "texto" /ruta: -r busca de forma recursiva y -n muestra el número de línea. Para limitar los tipos de archivo, añada --include="*.php".
¿Cómo reemplazar un texto en muchos archivos a la vez?
Combine la búsqueda con sed: grep -rl "viejo" . | xargs sed -i 's/viejo/nuevo/g'. Antes de hacerlo, conviene crear un commit o una copia de seguridad.
¿Cómo mostrar varias columnas separadas por tabulación en awk?
Defina el separador de salida: awk -v OFS='\t' '{print $1, $3}' archivo. Sin OFS, los campos se separan con un espacio.
¿Cómo eliminar los espacios al final de las líneas con sed?
El comando sed -i 's/[[:space:]]*$//' archivo elimina los espacios y tabulaciones finales de todas las líneas del archivo.
Este tema se explica a fondo y con práctica en el curso «Linux: с нуля до уверенного администрирования».
Ir al curso