entrada-y-salida
Entrada y salida
Section titled “Entrada y salida”Cómo se mueven los datos entre comandos, ficheros y el usuario: redirecciones, descriptores, pipes, here-documents, subshells.
Redirecciones
Section titled “Redirecciones”Cada comando dispone de tres canales estándar:
| Descriptor | Nombre | Por defecto |
|---|---|---|
0 |
stdin (entrada) | Teclado |
1 |
stdout (salida) | Pantalla |
2 |
stderr (errores) | Pantalla |
Operadores
Section titled “Operadores”| Operador | Efecto |
|---|---|
> fichero |
Redirige stdout a un fichero (lo sobrescribe) |
>> fichero |
Redirige stdout añadiendo al final |
< fichero |
Usa el fichero como stdin |
2> fichero |
Redirige stderr |
2>> fichero |
Redirige stderr añadiendo |
&> fichero |
Redirige stdout y stderr juntos (Bash) |
2>&1 |
Envía stderr al mismo sitio que stdout |
>&2 |
Envía stdout a stderr |
ls /etc > listado.txt # guarda la salidals /etc >> listado.txt # añadels /noexiste 2> errores.txt # solo erroresls /etc /noexiste > ok.txt 2> err.txt # separadosls /etc /noexiste &> todo.txt # ambos en el mismo ficherosort < desordenado.txt # entrada desde ficheroOrden de 2>&1
Section titled “Orden de 2>&1”El orden importa: se lee de izquierda a derecha.
comando > salida.txt 2>&1 # correcto: ambos van al ficherocomando 2>&1 > salida.txt # stderr va a la pantalla, solo stdout al ficheroMensajes de error a stderr
Section titled “Mensajes de error a stderr”echo "Error: fichero no encontrado" >&2Proteger ficheros de sobrescritura
Section titled “Proteger ficheros de sobrescritura”set -o noclobber # > no sobrescribe ficheros existentescomando >| fichero # fuerza la sobrescrituraVaciar o crear un fichero
Section titled “Vaciar o crear un fichero”> fichero.txt # lo deja vacío (o lo crea)Descriptores de fichero
Section titled “Descriptores de fichero”Además de 0, 1 y 2, Bash permite abrir descriptores propios (3 en adelante) con exec.
exec 3> salida.log # abre el descriptor 3 para escrituraecho "Primera línea" >&3echo "Segunda línea" >&3exec 3>&- # cierra el descriptor 3Lectura:
exec 4< datos.txtread -r primera <&4read -r segunda <&4exec 4<&-Redirigir todo el script
Section titled “Redirigir todo el script”exec > salida.log 2>&1 # desde este punto, toda la salida del script va al ficheroDuplicar descriptores
Section titled “Duplicar descriptores”exec 5>&1 # guarda el stdout original en el descriptor 5exec > fichero.txt # redirige stdoutecho "Va al fichero"exec 1>&5 5>&- # restaura stdout y cierra el 5Descriptores de red con /dev/tcp
Section titled “Descriptores de red con /dev/tcp”exec 3<> /dev/tcp/example.com/80printf 'HEAD / HTTP/1.0\r\nHost: example.com\r\n\r\n' >&3cat <&3exec 3>&-<> abre el descriptor en lectura y escritura.
El operador | conecta la stdout de un comando con la stdin del siguiente.
cat /etc/passwd | cut -d: -f1 | sort | head -n 5ps aux | grep sshls -l | wc -lIncluir stderr en la tubería
Section titled “Incluir stderr en la tubería”comando 2>&1 | grep "error"comando |& grep "error" # forma abreviada de BashCódigos de salida en una tubería
Section titled “Códigos de salida en una tubería”Por defecto, el código de salida es el del último comando. Un fallo anterior pasa desapercibido.
false | trueecho $? # 0
set -o pipefail # ahora la tubería falla si falla cualquier partefalse | trueecho $? # 1
echo "${PIPESTATUS[@]}" # códigos de cada comando de la última tuberíaCada comando de la tubería se ejecuta en una subshell
Section titled “Cada comando de la tubería se ejecuta en una subshell”Las variables modificadas dentro de la tubería no se ven fuera.
contador=0echo -e "a\nb" | while read -r l; do ((contador++)); doneecho "$contador" # 0Solución: usar redirección o process substitution (ver más abajo).
Here-doc y here-string
Section titled “Here-doc y here-string”Here-document
Section titled “Here-document”Pasa un bloque de texto de varias líneas como entrada.
cat <<EOFLínea 1Usuario: $USERFecha: $(date +%F)EOF| Variante | Efecto |
|---|---|
<<EOF |
Expande variables y comandos |
<<'EOF' |
Texto literal, sin expansión |
<<-EOF |
Elimina los tabuladores iniciales (permite indentar el bloque) |
cat <<'EOF'El símbolo $ y los comandos $(date) se muestran tal cual.EOFCrear un fichero desde un script:
cat > config.conf <<EOFservidor=example.compuerto=8080EOFPanel de ayuda:
function panel_ayuda(){ cat <<EOF
Uso: $0 [opciones] -m modo -h mostrar esta ayuda
EOF}El delimitador de cierre (EOF) debe estar solo en su línea, sin espacios delante (salvo con <<- y tabuladores).
Here-string
Section titled “Here-string”Pasa una cadena como stdin.
grep "root" <<< "$texto"read -r a b <<< "uno dos"bc <<< "2 + 3"/dev/null y tee
Section titled “/dev/null y tee”/dev/null
Section titled “/dev/null”Dispositivo que descarta todo lo que se escribe en él.
comando > /dev/null # oculta la salida normalcomando 2> /dev/null # oculta los errorescomando &> /dev/null # oculta todoUso típico: comprobar si algo funciona sin mostrar nada.
if ping -c1 -W1 192.0.2.1 &> /dev/null; then echo "Responde"fi/dev/zero produce bytes a cero; /dev/urandom produce bytes aleatorios.
Escribe la entrada en un fichero y la deja pasar por la salida estándar.
comando | tee salida.txt # muestra y guardacomando | tee -a salida.txt # añade al finalcomando 2>&1 | tee log.txt # incluye erroresEscribir en un fichero que requiere privilegios (la redirección la hace el usuario, no sudo):
echo "linea" | sudo tee -a /etc/fichero.conf > /dev/nullProcess substitution
Section titled “Process substitution”Permite usar la salida de un comando como si fuera un fichero.
diff <(sort a.txt) <(sort b.txt) # compara dos salidascomm -12 <(sort a.txt) <(sort b.txt) # líneas comunes<(comando): el resultado se lee como un fichero.>(comando): lo escrito se envía como entrada de un comando.
comando | tee >(grep error > errores.txt) > completo.txtEvitar la subshell en un while
Section titled “Evitar la subshell en un while”contador=0while read -r linea; do ((contador++))done < <(ls /etc)echo "$contador" # el valor se conservaProcess substitution es una característica de Bash, no existe en sh POSIX.
Subshells y agrupación de comandos
Section titled “Subshells y agrupación de comandos”Subshell: ( … )
Section titled “Subshell: ( … )”Ejecuta los comandos en un proceso hijo. Los cambios de variables y de directorio no afectan a la shell actual.
pwd( cd /tmp && pwd )pwd # sigue en el directorio original
x=1( x=2; echo "$x" ) # 2echo "$x" # 1Agrupación: { …; }
Section titled “Agrupación: { …; }”Ejecuta los comandos en la shell actual y permite redirigirlos en conjunto.
{ echo "Cabecera"; date; ls; } > informe.txt
[[ -f "$f" ]] || { echo "Falta $f" >&2; exit 1; }Sintaxis estricta: espacio después de { y ; (o salto de línea) antes de }.
( ) |
{ } |
|
|---|---|---|
| Proceso | Subshell | Shell actual |
Variables y cd |
No persisten | Persisten |
| Uso típico | Aislar cambios | Agrupar para redirigir o encadenar |
Sustitución de comandos
Section titled “Sustitución de comandos”$( ) también ejecuta en una subshell y captura su salida.
fecha=$(date +%F)ficheros=$(ls | wc -l)Segundo plano
Section titled “Segundo plano”( sleep 5; echo "Terminado" ) &