---
title: "Sed Cambia Mayúsculas: Minúsculas, Mayúsculas y Title Case con Ejemplos"
description: "Domina sed para cambiar mayúsculas: convierte texto a minúsculas, mayúsculas o title case con los modificadores \\L y \\U, el comando portable y, y ejemplos de batch seguros."
date: 2026-10-05
categories: ["linux"]
tags: ["sed","linux","command-line"]
---

import Button from "@components/widgets/Button.astro";
import Notice from "@components/widgets/Notice.astro";
import ListCheck from "@components/widgets/ListCheck.astro";
import Accordion from "@components/widgets/Accordion.astro";
import Tabs from "@components/widgets/Tabs.astro";
import Tab from "@components/widgets/Tab.astro";

¿Necesitas cambiar mayúsculas con sed? Esta guía cubre cada técnica de sed para cambiar mayúsculas: sed a minúsculas, sed a mayúsculas y sed a title case, construidas con el comando portable `y`, los modificadores `\L`/`\U` de GNU sed, y `\u` para caracteres sueltos. Todos los ejemplos están verificados contra GNU sed 4.9, con notas para GNU sed 4.10 y macOS/BSD donde el comportamiento difiere. Útil para limpiar datos, normalizar niveles de log y arreglar extensiones de archivo en batch.

El artículo va desde los comandos básicos hasta la edición in-place, el procesamiento por lotes y las trampas que hacen que sed a minúsculas "no funcione" (casi siempre es el shorthand de rango de `y` o el locale). Hay una chuleta al final si solo necesitas los comandos.

<ListCheck>
<ul>
<li>GNU sed 4.9+ (o 4.10, publicado 2026-04-21). Compruébalo con <code>sed --version</code>. El sed de macOS/BSD funciona para la mayoría de ejemplos, con límites anotados inline.</li>
<li>Un archivo de prueba para masticar. Nunca apuntes una primera corrida a datos que te importen.</li>
<li>Opcional: un repo git alrededor de los archivos que editas. <code>git checkout -- .</code> es el undo más limpio que sed tendrá jamás.</li>
<li>Cinco minutos y una terminal. Todo lo de abajo es copy-pasteable.</li>
</ul>
</ListCheck>

## ¿Qué es Sed?

**sed** (Stream Editor) es una herramienta de línea de comandos para manipulación de texto. Procesa la entrada línea a línea, lo que lo hace rápido para archivos grandes. Si aún estás construyendo tu toolkit, va junto a grep, awk y curl en la [chuleta de comandos esenciales de Linux](/linux-commands/).

Sed es genial para conversión de mayúsculas porque:

- Funciona no interactivamente (sin prompts)
- Maneja archivos grandes eficientemente (memoria constante, una línea cada vez)
- Puede apuntar a patrones o rangos de líneas específicos
- Funciona con pipes y otros comandos

Otras guías de sed de esta serie:

- [sed buscar y reemplazar](/sed-search-replace/)
- [borrar líneas con sed](/sed-delete-lines/)
- [insertar o añadir texto con sed](/sed-insert-append-text/)

## Cuándo Cambiar Mayúsculas con Sed

Situaciones comunes:

- **Limpieza de datos** - estandariza nombres o campos. `Jon`, `JON` y `jon` en la misma columna es un bug de calidad de datos esperando morder un join.
- **Formato de logs** - haz los niveles de error consistentes. `ERROR`, `Error` y `error` en un archivo de log rompen greps ingenuos y dashboards de logs.
- **Archivos de config** - algunas apps exigen claves en minúsculas, otras gritan todo en caps. Cambiar mayúsculas a mano en un archivo de 200 líneas es cómo ocurren los typos.
- **Procesamiento por lotes** - extensiones de archivo, headers HTTP, encabezados de columnas CSV, nombres de servicios docker-compose.

Sed es la herramienta correcta cuando la conversión es por líneas o apuntada por patrón. Si solo necesitas voltear un stream entero de mayúsculas a minúsculas sin condiciones, `tr` es más rápido (números en la sección [tr vs sed vs awk](#tr-vs-sed-vs-awk-qué-herramienta-para-conversión-de-mayúsculas)). La conversión de mayúsculas es barata en CPU en archivos pequeños y medianos de todas formas.

## Sed a Minúsculas y Mayúsculas: Los Comandos Básicos

Hay dos familias de conversión de mayúsculas en sed, más modificadores por carácter:

1. El comando `y` - portable, funciona en sed de GNU, BSD y macOS. Basado en listas de caracteres.
2. Los modificadores de reemplazo `\L` y `\U` - solo GNU sed. Más cortos, y se componen con otras sustituciones.
3. `\u`, `\l`, `\E` - solo GNU sed. Controlan mayúsculas por carácter, que es cómo se construye el title case.

La mayoría de flujos de cambio de mayúsculas en sed empiezan con uno de los dos primeros.

### Convertir Mayúsculas con el Comando y (Portable)

`y` translitera un conjunto de caracteres a otro. Debes listar cada carácter. Esto funciona donde funciona sed.

**Convertir a minúsculas:**

```sh
echo "HELLO WORLD" | sed 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'
# Output: hello world
```

**Convertir a mayúsculas:**

```sh
echo "hello world" | sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'
# Output: HELLO WORLD
```

<Notice type="warning" title="sed y nunca expande rangos">
A diferencia de <code>tr</code> y de los corchetes de regex, el comando <code>y</code> <strong>no</strong> expande rangos estilo <code>A-Z</code>. Este es el bug más común en snippets de conversión de mayúsculas con sed que hay por internet (y también vivió en este artículo antes):

```sh
echo "ABC az AZ 09" | sed 'y/A-Z/a-z/'
# Output: aBC az az 09   <- mal, y silenciosamente mal
```

Solo los caracteres literales <code>A</code>, <code>-</code> y <code>Z</code> se transliteran. Escribe siempre las listas completas de 26 caracteres.
</Notice>

<Notice type="warning" title="Las clases POSIX tampoco valen en y">
<code>y/[[:upper:]]/[[:lower:]]/</code> parece listo y no hace nada útil. La sintaxis de clases no se expande en <code>y</code>, y como ambas cadenas resultan tener la misma longitud, sed translitera en silencio los caracteres literales (<code>u</code> a <code>l</code>, <code>p</code> a <code>o</code>, <code>e</code> a <code>w</code>, <code>r</code> a <code>e</code>, ...) en vez de dar error. Usa las listas completas en <code>y</code>, o <code>[[:upper:]]</code>/<code>[[:lower:]]</code> dentro de una regex normal <code>s///</code> donde las clases sí funcionan.
</Notice>

### \L y \U de GNU Sed: Modificadores de Mayúsculas Más Cortos

GNU sed añade modificadores de mayúsculas en la parte de reemplazo de `s///`. `\L` pone en minúsculas todo lo que sigue, `\U` pone en mayúsculas todo lo que sigue.

**Convertir la línea entera a minúsculas (GNU sed):**

```sh
echo "HELLO WORLD" | sed 's/.*/\L&/'
# Output: hello world
```

**Convertir la línea entera a mayúsculas (GNU sed):**

```sh
echo "hello world" | sed 's/.*/\U&/'
# Output: HELLO WORLD
```

**Apuntar a líneas específicas:**

```sh
sed '/^ERROR/s/.*/\U&/' logfile.txt   # uppercases only lines starting with ERROR
```

Estos modificadores son solo-GNU. Están ausentes de las man pages de sed de FreeBSD y macOS, así que los scripts que deban correr en un Mac o BSD deben quedarse con `y` y listas completas. El `&` en el reemplazo significa "todo el texto coincidente", por eso `s/.*/\L&/` convierte la línea entera.

<Notice type="info" title="GNU sed 4.9 y 4.10">
Los ejemplos aquí se verificaron contra GNU sed 4.9 (el que traen sistemas clase Debian 12 / Ubuntu 24.04, publicado 2022-11-06). GNU sed <strong>4.10</strong> salió 2026-04-21, la primera release estable en unos tres años y medio. Cambios relevantes: <code>s///g</code> ya no hace pánico en líneas de más de 2 GB, se arregló una race TOCTOU en <code>sed -i --follow-symlinks</code> (actualiza si usas ese flag en directorios compartidos), y <code>--posix</code> ahora avisa sobre escapes backslash solo-GNU en <code>s</code>, lo que lo hace usable como linter de portabilidad para tus scripts. Comprueba tu versión con <code>sed --version</code>.
</Notice>

Una línea sobre locale: `LC_ALL=C sed ...` da comportamiento ASCII predecible, mientras que `\L`/`\U` necesitan un locale UTF-8 para manejar texto no-ASCII. Detalles en la [sección de gotchas](#gotchas-de-conversión-de-mayúsculas-en-sed-y-arreglos).

### Title Case y Capitalize: \u, \l y \E

Esta es la parte que la mayoría de recopilatorios de "conversión de mayúsculas con sed" se saltan, y es lo que los snippets estilo `\b[a-z]\+/\U&/g` hacen mal. GNU sed tiene cinco modificadores de mayúsculas en el reemplazo:

| Modificador | Efecto |
|----------|--------|
| `\L` | Minúsculas a todo lo que sigue, hasta `\U` o `\E` |
| `\l` | Minúscula al **siguiente carácter solo** |
| `\U` | Mayúsculas a todo lo que sigue, hasta `\L` o `\E` |
| `\u` | Mayúscula al **siguiente carácter solo** |
| `\E` | Para la conversión de mayúsculas iniciada por `\L` o `\U` |

![Diagrama de los modificadores de mayúsculas de GNU sed actuando sobre texto de ejemplo: backslash L pone en minúsculas el reemplazo, backslash U en mayúsculas, backslash l y backslash u tocan solo el siguiente carácter, y backslash E para la conversión](@assets/images/23/11/case-modifiers-map.svg)

**Title case en cada palabra** (primera letra de cada palabra en mayúscula, el resto en minúsculas):

```sh
sed -E 's/[a-z]+/\u&/g' filename.txt
# Input:  hello world
# Output: Hello World
```

Sin `-E` (BRE), lo mismo:

```sh
sed 's/[a-z][a-z]*/\u&/g' filename.txt
# Output: Hello World
```

Prefiere `-E` sobre la vieja grafía GNU `-r` para regex extendida. `-E` es el flag estándar POSIX hoy en día (bug 528 del Austin Group) y es lo que el propio manual de GNU recomienda para portabilidad.

**Poner en mayúscula la primera letra de cada línea:**

```sh
sed 's/./\u&/' filename.txt
# Input:  hello world
# Output: Hello world
```

**Poner en mayúsculas un token y dejar el resto de la línea igual:**

```sh
echo "user: admin status: ok" | sed 's/admin/\U&\E/'
# Output: user: ADMIN status: ok
```

**El bug de fuga de `\E`.** La conversión de mayúsculas sigue corriendo por el resto del reemplazo tras un grupo de captura a menos que la pares:

```sh
echo "host: db1" | sed -E 's/host: (.*)/HOST: \U\1 is up/'
# Output: HOST: DB1 IS UP   <- "is up" got uppercased too

echo "host: db1" | sed -E 's/host: (.*)/HOST: \U\1\E is up/'
# Output: HOST: DB1 is up   <- \E stops conversion after the group
```

Dos sutilezas más del manual y de pruebas:

- Con el flag `g`, la conversión de mayúsculas **no** se propaga de una coincidencia a la siguiente. Cada coincidencia reinicia limpio. **Sí** sigue corriendo dentro de un reemplazo a menos que `\E` la pare.
- Los límites de palabra no son portables. GNU sed acepta `\b`, `\<`, `\>`. El sed tradicional de BSD quiere `[[:<:]]` y `[[:>:]]` en su lugar. Si un ejemplo con `\b` silenciosamente no coincide con nada, normalmente es por eso (vale confirmarlo en tu Mac antes de confiar en cualquiera de las formas).

<Notice type="warning" title={"\\l y \\u tocan un carácter solo"}>
<code>s/[[:upper:]]/\l&amp;/g</code> no pone un archivo en minúsculas. Pone en minúscula solo el primer carácter de cada tirada de mayúsculas: <code>HELLO</code> se vuelve <code>hELLO</code>. Para conversión de línea entera usa <code>s/.*/\L&amp;/</code> o el comando <code>y</code> de lista completa.
</Notice>

### Coincidir Insensible a Mayúsculas con el Flag I

La conversión de mayúsculas y la coincidencia insensible a mayúsculas resuelven problemas distintos. Cuando quieres *encontrar* texto sin importar mayúsculas, GNU sed acepta el flag `I` en coincidencias regex (la `i` mayúscula también funciona):

```sh
sed 's/error/CRITICAL/gI' app.log
# matches Error, ERROR, error, and eRRor
```

Forma de dirección, por ejemplo borrar cada línea de warning sea cual sea su capitalización:

```sh
sed '/^warning/Id' app.log
```

Sorpresa de portabilidad: `I` está documentado como extensión GNU, pero el sed de FreeBSD y macOS también acepta `i`/`I` como flag de `s`. Eso lo hace *más* portable que `\L`/`\U` en la práctica. Si solo recuerdas un flag para scripts que viajan entre Linux y macOS, es este.

## Convertir Mayúsculas en Archivos: Edición In-Place y Apuntar Patrones

Trabajar con archivos se divide en dos casos: escribir el resultado en otro sitio (seguro), o editar el archivo in-place (rápido, con bordes afilados).

**Archivo entero a minúsculas (portable):**

```sh
sed 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' filename.txt > output.txt
```

**Archivo entero a minúsculas (GNU sed):**

```sh
sed 's/.*/\L&/' filename.txt > output.txt
```

**Archivo entero a mayúsculas (portable / GNU):**

```sh
sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' filename.txt > output.txt
sed 's/.*/\U&/' filename.txt > output.txt
```

**Apuntar a patrones específicos:**

```sh
sed '/^ERROR/s/.*/\U&/' logfile.txt        # only lines starting with ERROR
sed 's/\blinux\b/\U&/g' filename.txt       # only the word linux (GNU \b)
```

**Ejemplos prácticos:**

```sh
sed 's/^./\U&/' filename.txt               # uppercase first letter of each line
sed 's/\.[^.]*$/\L&/' filelist.txt         # lowercase the file extension
```

El ejemplo de la extensión importa: `s/\.[A-Z]*$/\L&/` solo coincide con extensiones que ya son todo caps, así que `photo.Jpg` se escapa. `s/\.[^.]*$/\L&/` coincide con cualquier extensión y la pone en minúsculas.

### Edición in-place

Prueba el comando sin `-i` primero. Siempre. Luego edita in-place, y guarda un backup en la primera pasada:

<Tabs>
<Tab name="GNU/Linux">
```sh
# edit in place
sed -i 's/.*/\L&/' filename.txt

# edit in place and keep a backup copy
sed -i.bak 's/.*/\L&/' filename.txt
ls filename.txt.bak    # confirm the backup exists before you trust this in a loop
```
</Tab>
<Tab name="macOS/BSD">
```sh
# -i REQUIRES a suffix argument on macOS/BSD (empty string = no backup)
sed -i '' 's/.*/\L&/' filename.txt

# cross-platform idiom: GNU treats .bak as a suffix, BSD as a backup extension
sed -i.bak 's/.*/\L&/' filename.txt
ls filename.txt.bak
```
</Tab>
</Tabs>

**Verifica antes de seguir:**

```sh
diff original.txt modified.txt
sed -n '1,5p' filename.txt
```

Si el archivo está en un repo git, sáltate el desorden de `.bak` desperdigados y usa [comandos git para deshacer cambios](/git-commands/) en su lugar:

```sh
sed -i 's/.*/\L&/' filename.txt
git diff --stat          # see what actually changed
git checkout -- .        # full rollback if the result is wrong
```

### Gotchas de sed -i: macOS, Inodos y Bind Mounts de Docker

GNU `sed -i` no edita tu archivo. Escribe la salida a un archivo temporal y lo renombra sobre el original. El nombre de archivo se queda; el inodo cambia. Eso tiene consecuencias:

- **Los hard links se rompen.** Cualquier cosa que aún apunte al inodo viejo ahora tiene contenido rancio.
- **`tail -f` pierde el archivo.** Sigue el inodo viejo. `tail -F` (mayúscula) reabre por nombre y sobrevive.
- **Los bind mounts de Docker de un solo archivo fallan.** El rename cruza una frontera de montaje y obtienes `sed: cannot rename ...: Device or resource busy`. Workaround: copia el archivo fuera, edítalo, cópialo de vuelta, o monta el directorio contenedor en vez del archivo suelto. (La redacción exacta del error vale una comprobación de 2 minutos en tu propia versión de Docker; mira los [comandos esenciales de Docker](/docker-commands/) para lo básico de montajes.) En contenedores Alpine/BusyBox, sed es BusyBox sed, no GNU sed: `-i` se comporta algo distinto y no apostaría un deploy a que `\L`/`\U` funcionen.
- **Necesitas disco libre.** Durante la reescritura, la copia temporal existe junto al original. Presupuesta más o menos 2x el tamaño del archivo.
- **Race de symlink en GNU sed antiguo.** `sed -i --follow-symlinks` tenía una vulnerabilidad TOCTOU (un symlink intercambiado entre resolución y apertura) arreglada en GNU sed 4.10. Si usas ese flag en directorios compartidos, actualiza.

<Notice type="warning" title="macOS y BSD: -i necesita un sufijo">
En macOS y FreeBSD, <code>sed -i</code> sin argumento es un error, y <code>sed -i '' '...'</code> significa "sin backup". Ambas man pages de BSD avisan de que una extensión de backup de longitud cero arriesga un archivo corrupto o parcial si el disco se llena a mitad de escritura, porque no hay backup de reserva. La forma segura multiplataforma es <code>sed -i.bak</code> en todas partes, luego borra los archivos <code>.bak</code> tras verificar.
</Notice>

## Conversión de Mayúsculas por Lotes entre Múltiples Archivos

Bucles for, `find` y `xargs` cubren casi todos los casos por lotes. Comilla tus variables y maneja espacios en nombres de archivo.

**Convertir todos los .txt a minúsculas:**

```sh
for file in *.txt; do
    sed -i.bak 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' "$file"
done
```

La sintaxis de bucle difiere por shell (word splitting, globbing, comportamiento de `set -e`). Si scripteas esto en algo que no sea bash, mira primero las [diferencias entre bash vs zsh vs fish](/fish-shell-vs-bash-vs-zsh/).

**Recursivo, seguro-con-espacios:**

```sh
find . -name "*.txt" -type f -print0 | xargs -0 sed -i.bak 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/'
```

**Find con -exec:**

```sh
# one sed invocation per file
find . -name "*.txt" -type f -exec sed -i.bak 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' {} \;

# batched, faster on large trees
find . -name "*.txt" -type f -exec sed -i.bak 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' {} +
```

`{} +` corre sed sobre muchos archivos por invocación y es el default correcto. `{} \;` es más fácil de leer en la salida de errores, un archivo cada vez.

**Procesamiento condicional:**

```sh
grep -l "ERROR" *.log | xargs sed -i.bak 's/error/ERROR/g'   # only files that contain ERROR
find . -name "*.conf" -exec sed -i.bak '/^#/!s/.*/\L&/' {} \;  # lowercase lines that are not comments
```

**Ejemplos prácticos:**

```sh
# normalize source files
find ./src -name "*.php" -exec sed -i.bak 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' {} +

# shout every log level in place
find ./logs -name "*.log" -exec sed -i.bak 's/\b\(info\|warn\|error\|debug\)\b/\U&/g' {} +
```

<ListCheck>
<ul>
<li><strong>Backup primero.</strong> <code>find . -name "*.txt" -exec cp &#123;&#125; &#123;&#125;.backup \;</code> o confía en git.</li>
<li><strong>Prueba en archivos de muestra.</strong> <code>find . -name "sample*.txt" -exec sed 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' &#123;&#125; \;</code> (sin <code>-i</code> en la corrida de prueba).</li>
<li><strong>Usa control de versiones o archivos comprimidos</strong> antes de cualquier reescritura por lotes de archivos trackeados.</li>
<li><strong>Comprueba resultados con diff</strong> antes de borrar nada: <code>diff original.txt modified.txt</code>.</li>
</ul>
</ListCheck>

### Verifica los Resultados tras la Conversión por Lotes

Las ediciones por lotes son donde los bugs silenciosos (como `y/A-Z/a-z/`) hacen más daño. Verifica en vez de esperar:

```sh
# after lowercasing a tree: confirm nothing uppercase remains
grep -rlE '[[:upper:]]' ./converted || echo "clean"

# eyeball the actual changes against the originals
diff -ru ./orig ./converted | head

# in a git repo: summary first, then undo if needed
git diff --stat
git checkout -- .
```

<Notice type="success" title="Verifica antes de limpiar">
Corre el grep, el diff y <code>git status</code> <strong>antes</strong> de borrar cualquier archivo <code>.bak</code> o <code>.backup</code>. Si el grep no imprime nada, el diff coincide con lo que pretendías, y git muestra solo los archivos esperados, entonces quita los backups.
</Notice>

## Gotchas de Conversión de Mayúsculas en Sed (y Arreglos)

Cuatro modos de fallo cubren casi todo reporte de "sed a minúsculas no funciona".

**1. `y/A-Z/a-z/` no hace nada útil.** `y` nunca expande rangos ni clases POSIX. Resumen de la [sección del comando y](#convertir-mayúsculas-con-el-comando-y-portable): usa las listas completas de 26 caracteres, siempre.

**2. La colación del locale se come tus clases de caracteres.** `[a-z]` no es ASCII `a` a `z` bajo cada locale. En un locale danés `^[a-z]$` puede coincidir con `aa` (un símbolo de colación único); los locales españoles hacen cosas parecidas con `ll`. Si una coincidencia parece imposible o demasiado ansiosa:

```sh
LC_ALL=C sed 's/[A-Z]/\l&/g' file.txt     # deterministic ASCII behavior
sed 's/[[:upper:]]/\l&/g' file.txt        # POSIX classes in s/// are locale-aware and explicit
```

<Notice type="warning" title="El locale es el culpable habitual">
Si una conversión de mayúsculas "funciona en la terminal pero no en cron" (o al revés), compara <code>locale</code> en ambos entornos. Para trabajo solo-ASCII, corre <code>LC_ALL=C sed ...</code>. Las clases POSIX como <code>[[:upper:]]</code> funcionan dentro de regexes <code>s///</code> y son la elección más clara cuando quieres decir "todas las letras mayúsculas". Siguen sin ser válidas en <code>y</code>.
</Notice>

**3. Texto Unicode y multibyte.** El viejo consejo "sed es solo-ASCII, usa perl" está medio mal:

```sh
echo "ÉCOLE École naïve" | LC_ALL=C.UTF-8 sed 's/.*/\L&/'
# Output: école école naïve   <- GNU \L is locale-aware under a UTF-8 locale

echo "ÉCOLE École naïve" | LC_ALL=C sed 's/.*/\L&/'
# mangled multibyte output   <- C locale treats bytes, not characters

echo "ÉCOLE École naïve" | tr '[:upper:]' '[:lower:]'
# Output: École naïve        <- tr is byte-oriented and never touches É
```

Así que: para Unicode, `\L`/`\U` de GNU bajo un locale UTF-8 funciona. `tr` no. `perl` y `gawk` también funcionan si ya los llevas. El comando `y` es basado en listas e impráctico para Unicode.

**4. `sed -i` intercambia el inodo.** Resumen de los [gotchas de sed -i](#gotchas-de-sed--i-macos-inodos-y-bind-mounts-de-docker): los hard links se rompen, `tail -f` pierde el archivo, los bind mounts de Docker de un solo archivo pueden fallar en el rename. Si el archivo importa, guarda el backup o el historial de git.

## tr vs sed vs awk: ¿Qué Herramienta para Conversión de Mayúsculas?

Benchmark rápido sobre un archivo de 77 MB / 2.000.000 de líneas (GNU sed 4.9, tiempo de reloj; tus números variarán, trátalos como orden de magnitud):

| Comando | Tiempo | Notas |
|---------|------|-------|
| `tr '[:upper:]' '[:lower:]' < file` | 0.05 s | Stream entero, sin condiciones |
| `sed 'y/'` con las listas completas de 26 chars | 0.26 s | Portable, ~5x tr |
| `sed 's/.*/\L&/' file` | 1.87 s | Cómodo, ~37x tr |

Reglas de dedo, no dogma:

- **Volcado de stream entero, nada más** - usa `tr`. Gana en cada trabajo de varios GB.
- **Direcciones de línea, patrones o edición in-place** - usa `sed`.
- **Lógica de campo o columna** (las mayúsculas dependen de qué columna) - usa `awk` con `tolower()` / `toupper()`.
- **Casos extremos Unicode** - `\L`/`\U` de GNU bajo un locale UTF-8, o `perl` / `gawk`.

![Flujo de decisión para herramientas de conversión de mayúsculas: los volcados de stream entero van a tr, el apunte por línea o patrón y la edición in-place van a sed, la lógica de campo va a awk, los casos extremos Unicode van a perl o gawk](@assets/images/23/11/tool-choice-flow.svg)

Para completar: GNU sed 4.2.2+ tiene `sed -z`, que lee "líneas" separadas por NUL en vez de separadas por newline. Ese es el truco para entrada multilínea o delimitada por NUL, por ejemplo poner en minúsculas los valores dentro de un stream `find -print0` separado por NUL. Y recuerda la nota de disco de antes: el `-i` in-place necesita más o menos 2x el tamaño del archivo en espacio libre mientras existe la copia temporal.

## Chuleta de Cambio de Mayúsculas en Sed

```sh
# lowercase, portable (full lists - never y/A-Z/a-z/)
sed 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' file.txt

# uppercase, portable
sed 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' file.txt

# lowercase / uppercase, GNU sed
sed 's/.*/\L&/' file.txt
sed 's/.*/\U&/' file.txt

# title case (first letter of each word), GNU sed
sed -E 's/[a-z]+/\u&/g' file.txt

# capitalize first letter of each line
sed 's/./\u&/' file.txt

# uppercase one token, stop conversion with \E
sed 's/admin/\U&\E/' file.txt

# case-insensitive match, then convert
sed 's/error/CRITICAL/gI' app.log

# in-place with backup (GNU + BSD)
sed -i.bak 's/.*/\L&/' file.txt
# macOS/BSD alternative: sed -i '' 's/.*/\L&/' file.txt

# batch, space-safe
find . -name '*.txt' -type f -exec sed -i.bak 'y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/' {} +

# verify nothing uppercase remains
grep -rlE '[[:upper:]]' . || echo "all lowercase"
```

| Comando | Función | Portabilidad |
|---------|----------|-------------|
| `y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/` | Minúsculas línea entera | GNU, BSD, macOS |
| `y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/` | Mayúsculas línea entera | GNU, BSD, macOS |
| `s/.*/\L&/` | Minúsculas línea entera | solo GNU |
| `s/.*/\U&/` | Mayúsculas línea entera | solo GNU |
| `s/./\u&/` | Mayúscula primera letra de línea | solo GNU |
| `sed -E 's/[a-z]+/\u&/g'` | Title case cada palabra | solo GNU |
| `s/admin/\U&\E/` | Mayúsculas un token, resto igual | solo GNU |
| `s/error/ERROR/gI` | Coincidencia insensible a mayúsculas | GNU + FreeBSD + macOS |
| `sed -i.bak '…'` | Edición in-place con backup | GNU + BSD |
| `sed -i '' '…'` | Edición in-place, sin backup | solo macOS/BSD |
| `grep -rlE '[[:upper:]]'` | Verificar que las minúsculas funcionaron | en cualquier sitio |

<ListCheck>
<ul>
<li>Prueba cada comando sin <code>-i</code> primero.</li>
<li><code>y</code> necesita listas completas de 26 caracteres. Los rangos no se expanden.</li>
<li>Usa <code>\u</code> (no <code>\U</code>) para title case. Una letra versus el resto de la cadena.</li>
<li><code>\E</code> para la conversión de mayúsculas. Sin él, la conversión se fuga más allá de tu grupo de captura.</li>
<li>Verifica con <code>grep</code> y <code>diff</code>, deshaz con <code>git checkout</code>.</li>
</ul>
</ListCheck>

<Button text="Chuleta de comandos esenciales de Linux" link="/linux-commands/" variant="solid" color="blue" size="md" icon="arrow-right" />

## FAQ de Cambio de Mayúsculas en Sed

<Accordion label={"¿y o \\L/\\U - cuál debería usar?"} group="faq" expanded="true">
Usa el comando `y` de lista completa cuando el script tenga que correr en sed de BSD o macOS, o cuando quieras el más rápido de los dos (unas 7x más rápido que `\L` en archivos grandes, según el benchmark rápido de arriba). Usa `\L`/`\U` en GNU sed cuando ya estés dentro de una sustitución `s///` o quieras la sintaxis más corta. Nunca escribas `y/A-Z/a-z/` - solo translitera los caracteres literales `A`, `-` y `Z`.
</Accordion>

<Accordion label="¿Cómo apunto a patrones o líneas específicas?" group="faq">
Prefija la sustitución con una dirección. `sed '/^ERROR/s/.*/\U&/' file.txt` convierte solo las líneas que empiezan por ERROR. `sed 's/\blinux\b/\U&/g' file.txt` convierte solo la palabra linux (`\b` de GNU; el sed de BSD tradicionalmente quiere `[[:<:]]`/`[[:>:]]`). Para coincidencia insensible a mayúsculas, añade el flag `I`: `sed 's/error/CRITICAL/gI' app.log`.
</Accordion>

<Accordion label="¿Puedo deshacer cambios de sed?" group="faq">
Sed no tiene undo integrado, pero puedes hacer cada edición reversible. O guarda un backup (`sed -i.bak '…' file.txt`) o trabaja dentro de un repo git y retrocede con `git checkout -- file.txt`. Lo único que no puedes hacer es recuperar una edición in-place de la nada después del hecho - así que haz el backup o el commit antes, no después.
</Accordion>

<Accordion label="¿Cómo manejo nombres de archivo con espacios?" group="faq">
Usa delimitadores NUL de extremo a extremo: `find . -name "*.txt" -type f -print0 | xargs -0 sed -i.bak 'command'`. En un bucle for, comilla la variable (`"$file"`) y considera `shopt -s nullglob` para que un glob vacío no pase un `*.txt` literal a sed.
</Accordion>

<Accordion label="¿Sed maneja conversión de mayúsculas Unicode?" group="faq">
El comando `y` no - es basado en listas de caracteres e impráctico más allá de ASCII. `\L`/`\U` de GNU sed sí, bajo un locale UTF-8: `echo "ÉCOLE" | LC_ALL=C.UTF-8 sed 's/.*/\L&/'` da `école`. Bajo el locale C el mismo comando mutila la salida multibyte. `tr` es orientado a bytes y nunca toca `É`. Para trabajo Unicode más pesado, `perl` o `gawk` son la respuesta habitual.
</Accordion>

<Accordion label="¿Cómo pongo en mayúscula la primera letra de cada palabra o línea?" group="faq">
Para cada palabra (title case), GNU sed: `sed -E 's/[a-z]+/\u&/g' file.txt` convierte `hello world` en `Hello World`. Para solo el primer carácter de cada línea: `sed 's/./\u&/' file.txt` convierte `hello world` en `Hello world`. Recuerda que `\u` toca un carácter solo - `\U` pondría en mayúsculas todo el resto de la línea.
</Accordion>

<Accordion label="¿Por qué mi comando sed -i de macOS falla?" group="faq">
Porque el sed de BSD requiere un argumento de sufijo: `sed -i 's/a/b/' file` es un error, `sed -i '' 's/a/b/' file` edita sin backup, y `sed -i.bak 's/a/b/' file` guarda uno. La forma `.bak` funciona en GNU sed también, así que úsala en scripts portables. Y en ambas plataformas, recuerda que `-i` reemplaza el archivo vía rename - el inodo cambia, los hard links se rompen, y un bind mount de Docker de un solo archivo puede rechazar el rename.
</Accordion>