código·java·oracle
Oracle y SQL

SET ECHO ON en SQL*Plus: cómo preparar un script que se ejecuta solo

SET ECHO ON hace que SQL*Plus escriba cada comando de un script antes de ejecutarlo, pero solo cuando el script se lanza con @, @@ o START. Con TERMOUT, VERIFY, SERVEROUTPUT y WHENEVER SQLERROR forma la cabecera de cualquier script que deba correr de noche sin nadie delante.

publicado octubre de 2026 revisado octubre de 2026 1541 palabras

La respuesta corta: SET ECHO ON le pide a SQL*Plus que muestre cada comando de un script justo antes de ejecutarlo, de modo que el log cuenta qué sentencia produjo cada resultado y cada error. Solo actúa sobre scripts lanzados con @, @@ o START, y su valor por defecto es OFF. Es la primera línea de una cabecera corta que convierte un fichero .sql en un proceso desatendido fiable, junto a cuatro o cinco variables más y una orden de salida ante errores.

Oficina técnica vacía de madrugada, una lámpara de escritorio encendida sobre una mesa de madera con una libreta cerrada de tapas lisas y una taza de café, ventanas oscuras con luces lejanas de la ciudad
Una carga nocturna no tiene a nadie delante: por la mañana, el log es lo único que queda.

¿Qué hace exactamente SET ECHO ON en SQL*Plus?

La referencia de variables SET de la guía de SQL*Plus lo define con precisión: ECHO controla si se repiten en pantalla los comandos de un script ejecutado con @, @@ o START. Con ON, cada sentencia aparece antes de su salida; con OFF, solo se ve la salida. Donde cambia todo es en el fichero de log de una carga nocturna: sin eco, un ORA-00001 aparece huérfano entre cuarenta mensajes de «1 row created.» y toca adivinar qué INSERT lo provocó; con eco, la sentencia culpable está justo encima del error.

Un log escrito con ECHO ON es además la prueba de qué se ejecutó, con qué valores y en qué orden. Para saber cómo está la sesión basta SHOW ECHO, o SHOW ALL para el inventario completo de variables.

¿Por qué SET ECHO ON no muestra nada al redirigir el script?

La respuesta está en la misma página de referencia: ECHO no afecta a los comandos que se escriben de forma interactiva ni a los que llegan a SQL*Plus redirigidos desde el sistema operativo. Si el script entra por la entrada estándar, con sqlplus usuario@bd < carga.sql o con un here document de shell, para SQL*Plus esas líneas son tecleo y no un script, así que el eco no se aplica. Lo mismo le pasa a SET TERMOUT OFF: en ese modo tampoco silencia nada.

La solución es pasar el fichero como script, en la propia línea de órdenes:

Shelllanzar_carga.sh
#!/bin/sh
# CONEXION guarda la cadena de conexion, idealmente /@ALIAS con un wallet
sqlplus -s -L "$CONEXION" @/opt/scripts/carga_nocturna.sql 2026-10-19
codigo=$?
if [ "$codigo" -ne 0 ]; then
  echo "carga_nocturna.sql ha fallado (codigo $codigo)" >&2
  exit 1
fi

Cada opción tiene su motivo. -s es el modo silencioso: quita el banner y los prompts, que solo ensucian un log. -L intenta la conexión una sola vez en lugar de volver a pedir usuario y contraseña, lo que evita que un proceso de cron se quede esperando unas credenciales que nadie va a escribir. El argumento que sigue al nombre del script llega dentro de él como &1. Y la contraseña no debería ir en la línea de órdenes: en Unix, los argumentos de un proceso son visibles para otros usuarios con ps.

ECHO, TERMOUT, VERIFY, SERVEROUTPUT: ¿qué controla cada variable?

Cuatro variables deciden qué se ve y qué no en un script; otras tres afinan el fichero de salida. Sus valores por defecto explican casi todas las sorpresas: un script recién escrito no muestra sus comandos, sí muestra las líneas de sustitución y se traga los mensajes de DBMS_OUTPUT.

VariableQué controlaPor defectoEn un script desatendido
ECHORepite cada comando del script antes de ejecutarloOFFON, para que el log se pueda leer
TERMOUTMuestra en pantalla la salida de los comandos del scriptONOFF cuando todo va a un SPOOL
VERIFYLista la sentencia antes y después de sustituir variablesONOFF, salvo para depurar
FEEDBACKMensajes de filas afectadas y de confirmación6 (umbral de filas)ON en un log, OFF en un fichero de datos
SERVEROUTPUTSalida de DBMS_OUTPUT.PUT_LINEOFFON si hay bloques PL/SQL que informan
DEFINEPrefijo de las variables de sustitución&OFF si los datos contienen & y no hay parámetros
TRIMSPOOLBlancos al final de cada línea del SPOOLOFFON

VERIFY merece una línea aparte. Cuando un script usa &1 o &fecha, SQL*Plus imprime por defecto la sentencia antes y después de sustituir el valor, con las etiquetas old y new. Es útil para depurar y puro ruido en un log de producción: SET VERIFY OFF lo elimina. El caso contrario es SET DEFINE OFF, que desactiva la sustitución entera. Hace falta cuando el script inserta textos como 'AT&T': con DEFINE activo, SQL*Plus toma &T por una variable y pide un valor para ella.

SERVEROUTPUT es el tercer clásico. Sin SET SERVEROUTPUT ON, todo DBMS_OUTPUT.PUT_LINE de un bloque PL/SQL se pierde sin aviso. En la documentación de 19c el búfer por defecto es UNLIMITED, y Oracle aclara que no reserva memoria por adelantado, así que no hay motivo para fijar un tamaño; el límite que sí existe es de 32 767 bytes por línea.

Manos de un técnico conectando un cable de red azul en un armario técnico con pilotos verdes encendidos, oficina desenfocada al fondo
El script corre lejos de cualquier pantalla: lo que pase allí solo se sabrá por su log.

¿Cómo se detiene un script de SQL*Plus al primer error?

Con WHENEVER SQLERROR EXIT, colocado antes de la primera sentencia. Por defecto SQL*Plus no se para ante un error: imprime el ORA- y sigue con la línea siguiente, que muchas veces opera sobre datos que la anterior debía haber preparado. Tres detalles de la documentación de WHENEVER SQLERROR y del comando EXIT cambian la forma de escribirlo:

  • Solo reacciona a errores de SQL y de PL/SQL. Un error del propio SQL*Plus, como el SP2- de un SET mal escrito, no dispara la salida. Para registrarlos existe SET ERRORLOGGING ON, que guarda los errores ORA, PLS y SP2 en la tabla SPERRORLOG del esquema.
  • Si no se dice otra cosa, la salida confirma lo pendiente. La cláusula EXIT de WHENEVER sigue la sintaxis del comando EXIT, y un EXIT sin cláusulas hace COMMIT, porque EXITCOMMIT vale ON por defecto. Un script que falla a mitad de una carga confirmaría la mitad cargada. Por eso se escribe ROLLBACK de forma explícita.
  • El código de salida cabe en un byte. EXIT SQL.SQLCODE devuelve el número del error, pero en Unix el código de retorno solo dispone de un byte, de 0 a 255. Un ORA-00942 llega al shell como 174 (942 menos 768) y un ORA-01536, cuota de tablespace superada, llega como 0, porque 1536 es exactamente seis veces 256: el shell lo lee como un éxito. EXIT FAILURE devuelve siempre un código de fallo, y el número del ORA ya queda escrito en el log.

La pareja de WHENEVER SQLERROR es WHENEVER OSERROR, que sale de SQL*Plus cuando el error lo genera el sistema operativo. Conviene distinguir además el script que falla del script que se queda quieto: una sentencia que espera, sin error y sin avanzar, casi nunca es culpa de SQL*Plus sino de un candado, porque otra sesión retiene las filas que la carga quiere tocar. El diagnóstico está en cómo localizar la sesión que bloquea un objeto.

Una cabecera para cron o para un pipeline

Todo lo anterior cabe en una docena de líneas que se copian al principio de cada script desatendido. Este es el esqueleto de una carga nocturna que recibe la fecha como primer argumento:

SQLcarga_nocturna.sql
-- carga_nocturna.sql: recibe la fecha de carga en &1
WHENEVER OSERROR  EXIT FAILURE ROLLBACK
WHENEVER SQLERROR EXIT FAILURE ROLLBACK
SET ECHO ON
SET VERIFY OFF
SET FEEDBACK ON
SET SERVEROUTPUT ON
SET TRIMSPOOL ON
SET LINESIZE 200
SET PAGESIZE 100
SET TERMOUT OFF
SPOOL /var/log/oracle/carga_nocturna_&1..log

DEFINE fecha_carga = '&1'

-- aqui van las sentencias de la carga, por ejemplo un MERGE
-- que filtre con TO_DATE('&fecha_carga', 'YYYY-MM-DD')

SPOOL OFF
EXIT SUCCESS COMMIT

Tres decisiones de esa cabecera son deliberadas. Los dos WHENEVER van antes que nada, para que ninguna sentencia corra sin red. TERMOUT OFF se coloca justo antes del SPOOL: la salida de cron queda vacía cuando todo va bien y el detalle vive en el log, con un nombre fechado gracias al punto que cierra la variable en &1..log. Y el EXIT final es explícito: sin él, al terminar el script SQL*Plus vuelve a su prompt a esperar órdenes, y lo que ocurra con la transacción pendiente deja de estar escrito en el script.

Si el contenido es un MERGE, la sentencia en sí está explicada en el upsert de Oracle con MERGE INTO; esta cabecera solo se ocupa de que su ejecución deje rastro y se detenga a tiempo. Para la sesión interactiva de cada día, con LINESIZE, PAGESIZE, TIMING, AUTOTRACE y el fichero login.sql, la referencia es el comando SET de SQL*Plus para configurar la sesión.

Un script desatendido no se juzga por lo que hace cuando todo va bien, sino por lo que deja escrito cuando algo falla a las tres de la madrugada.

¿Cómo se guarda y se restaura la configuración de SET?

Cuando un script se llama con @ desde una sesión interactiva, sus SET siguen aplicados al terminar: quien lo lanzó se encuentra de pronto sin cabeceras de columna o sin salida en pantalla. STORE SET resuelve el problema, porque guarda los atributos del entorno actual en un script del sistema operativo que después se vuelve a ejecutar con @, siempre que el script intermedio no termine con EXIT:

SQLrestaurar_entorno.sql
STORE SET /tmp/entorno_previo.sql REPLACE
@/opt/scripts/informe_semanal.sql
@/tmp/entorno_previo.sql

Con @@, SQL*Plus busca el script hijo en la misma ruta que el script que lo llama: una carpeta de scripts se mueve entera sin reescribir rutas, y los hijos heredan la cabecera que fijó el script principal.

Preguntas frecuentes

¿Cuál es el valor por defecto de SET ECHO en SQL*Plus?

OFF. Un script lanzado con @ muestra su salida pero no sus comandos hasta que se escribe SET ECHO ON. El valor activo se consulta con SHOW ECHO.

¿Sirve SET ECHO ON en una sesión interactiva?

No cambia nada. ECHO solo afecta a los comandos de scripts ejecutados con @, @@ o START; los comandos tecleados o redirigidos desde el sistema operativo no se repiten, haya eco o no.

¿Qué diferencia hay entre SET ECHO y SET TERMOUT?

ECHO decide si se muestran los comandos del script; TERMOUT decide si se muestra en pantalla la salida que producen. Con ECHO ON y TERMOUT OFF la pantalla queda en silencio y el fichero de SPOOL recoge comandos y resultados.