- L'ús de SETLOCAL, les extensions d'ordre i l'expansió retardada permet aïllar l'entorn i controlar amb precisió les variables en scripts batch complexos.
- ERRORLEVEL és la base del maneig d'errors, i combinant-ho amb operadors com || s'aconsegueix un codi més net i llegible a CMD.
- L'expansió retardada resulta imprescindible per a bucles i estructures dinàmiques, com ara jocs o manipulacions de matrius simulades en arxius per lots.
- El domini de subrutines, control de caràcters especials i patrons avançats de batch converteix el CMD en una eina vàlida per a automatitzacions robustes.
Treballar amb CMD a nivell avançat implica molt més que llançar un parell de ordres solts: quan comences a utilitzar arxius per lots complexos, l'expansió retardada de variables, el control d'extensions i un maneig d'errors fi marquen la diferència entre un script robust i un que falla en silenci o tanca la consola sense avisar. En aquest article ens posarem fins al fons en aquest tema, veient truquets reals i matisos que sovint no apareixen a les guies bàsiques.
Si mai has patit que la finestra es tanqui de cop en executar el teu .bat, que un bucle FOR no faci servir els valors esperats o que ERRORLEVEL es comporti “rar”, t'interessa seguir llegint. Repassarem què fan realment comandes com SETLOCAL, ENDLOCAL, l'expansió retardada (delayed expansion), operadors com || per a control d'errors, i alguns patrons típics usats en scripts avançats, inclosos exemples de jocs o utilitats que manipulen moltes variables dinàmiques.
Què és SETLOCAL i per què és clau en arxius per lots avançats
La comanda SETLOCAL és la base per controlar l'entorn dins d'un script per lots a Windows. La seva funció principal és iniciar un “àmbit local” de variables d'entorn on els canvis que facis deixaran d'existir quan s'executi ENDLOCAL o s'arribi al final del fitxer .bat.
La sintaxi bàsica de SETLOCAL és la següent, i sobre ella es recolzen moltes de les tècniques més avançades amb CMD:
sintaxi: setlocal
Mitjançant aquesta sintaxi pots controlar dues coses molt importants: les extensions de comandes de CMD i l'expansió retardada de variables d'entorn. Ambdós ajustaments s'apliquen des del punt on crides a SETLOCAL fins al ENDLOCAL coincident, sense afectar la configuració global de la sessió de consola fora daquest bloc.
És important entendre que fer servir SETLOCAL fora d'un .bat (per exemple, teclejant-lo a mà a la consola interactiva) no té cap efecte real. El seu propòsit està pensat per a scripts, on necessites aïllar canvis en variables com PATH, rutes temporals, opcions de la teva aplicació, etc., sense deixar brut l'entorn de l'usuari després de finalitzar el fitxer per lots.
Una característica clau de SETLOCAL és que actua de forma imbricada: en pots tenir diversos SETLOCAL y ENDLOCAL dins del mateix script, un dins un altre. Cada nivell imbricat guarda un “snapshot” de l'entorn, i en executar ENDLOCAL es restaura sempre l'estat previ a l'últim SETLOCAL.

Paràmetres de SETLOCAL: extensions i expansió retardada
SETLOCAL pot rebre paràmetres per activar o desactivar tant les extensions de comandes com l'expansió retardada de variables d'entorn. Els paràmetres disponibles són:
- enableextensions: habilita les extensions d'ordres fins al
ENDLOCALcorresponent, sense importar com estiguessin abans. - disableextensions: desactiva aquestes extensions fins al següent
ENDLOCAL. - enabledelayedexpansion: activa l'expansió retardada de variables d'entorn.
- disabledelaiedexpansion: desactiva aquesta expansió.
- /?: mostra l'ajuda de SETLOCAL al símbol de sistema.
Les extensions d'ordres de CMD amplien el comportament de moltes ordres clàssiques, com IF, FOR, SET o CALL. Scripts avançats solen dependre d'aquestes extensions, per la qual cosa és habitual veure blocs del tipus:
Exemple: setlocal enableextensions enabledelayedexpansion
REM aquí va el código avanzado que necesita extensiones y delayed expansion
endlocal
L'expansió retardada (delayed expansion) és fonamental quan es treballa amb bucles i variables que canvien dins un FOR o de blocs amb parèntesis. En lloc d'usar %variable%, s'utilitzen exclamacions !variable!, el que permet que el valor s'avaluï en temps d'execució de cada iteració, i no quan es parseja tot el bloc.
Un detall subtil però molt útil és que SETLOCAL modifica la variable ERRORLEVEL en funció de com s'anomeni: si s'especifiquen els arguments enableextensions/disableextensions o enabledelayedexpansion/disabledelayedexpansion, ERRORLEVEL s'estableix a 0. Si s'executa sense paràmetres, ERRORLEVEL passa a 1. Aquest comportament es pot aprofitar per detectar si hi ha certes característiques disponibles.
Comportament d'ERRORLEVEL i detecció d'extensions disponibles
La variable ERRORLEVEL és el mecanisme clàssic per saber si una ordre va tenir èxit o va fallar. Tot i això, CMD té algunes peculiaritats quan les extensions estan deshabilitades, i és fàcil emportar-se sorpreses si s'assumeix que ERRORLEVEL sempre s'actualitza automàticament.
Un patró típic documentat consisteix a inicialitzar ERRORLEVEL a un valor diferent de zero usant l'ordre VERIFY amb un argument no vàlid, ia partir d'aquí utilitzar SETLOCAL per comprovar la capacitat dactivar extensions. L'exemple clàssic seria una cosa així:
Exemple: verify other 2>nul
setlocal enableextensions
if errorlevel 1 echo Unable to enable extensions
En aquest fragment es fa el següent: primer, l'ús de verify other amb un paràmetre no admès obliga CMD a assignar a ERRORLEVEL un valor diferent de zero. Després, SETLOCAL enableextensions hauríeu de posar ERRORLEVEL a 0 si heu pogut activar les extensions. Per tant, si després d'aquesta comanda ERRORLEVEL es manté en 1, s'interpreta que les extensions no estan disponibles.
Això és perquè, quan les extensions d'ordres estan desactivades, CMD no ajusta ERRORLEVEL de la manera habitual per a algunes operacions. Per això cal aquest petit truc previ amb verify. En scripts robusts que hagin de córrer en entorns “limitats” o heretats, aquest tipus de comprovacions pot ser molt útil.
Tingueu en compte també que SETLOCAL fora d'un arxiu per lots no us ajudarà a gestionar ERRORLEVEL en una sessió interactiva, perquè l'efecte de localització de l'entorn només està pensat per al context d'execució d'un script.
Exemple pràctic de SETLOCAL: modificar PATH temporalment
Una de les aplicacions més típiques de SETLOCAL és tocar la variable PATH dins un .bat per llançar una aplicació o script auxiliar, però sense deixar aquesta modificació activa per a la resta de la sessió.
Un exemple d'script complet, que arrenca un programa de xarxa “superapp”, redirigeix la seva sortida a un fitxer i després obre aquest fitxer al Bloc de notes, es podria veure així:
Script d'exemple: rem *Begin Comment
rem Este programa inicia el programa por lotes superapp en la red,
rem redirige la salida a un archivo y muestra el archivo
rem en el Bloc de notas.
rem *End Comment
@echo off
setlocal
set path=g:\programs\superapp;%path%
call superapp > c:\superapp.out
endlocal
start notepad c:\superapp.out
En aquest script, totes les modificacions del PATH es limiten al bloc protegit per SETLOCAL y ENDLOCAL. Fora del tram, l'entorn de l'usuari (inclòs PATH) queda com estava. Aquest patró es fa servir moltíssim quan s'integren eines de tercers sense voler “embrutar” l'entorn global.
Fixa't també en l'ús de CALL per executar superapp, la qual cosa permet que, en acabar, el flux de l'arxiu per lots continuï amb normalitat, redirigint la sortida a un fitxer i, al final, llançant el Bloc de notes per mostrar-la.
Maneig d'errors a batch: ERRORLEVEL, IF i l'operador ||
En script per lots, el maneig derrors clàssic consisteix a consultar ERRORLEVEL just després de cada ordre “crític”. Un esquema molt habitual és el següent:
patró: copy blah ..\test
if %errorlevel% neq 0 exit /b %errorlevel%
Aquí el que es fa és executar una còpia i, si ERRORLEVEL és diferent de 0, sortir de l'script retornant aquest mateix codi d'error. És la manera més explícita i compatible, però comença a omplir l'script de blocs IF repetitius que embruten la lectura.
Per netejar el codi molts usuaris avançats han adoptat l'operador lògic ||. Aquest operador executa la segona ordre només si la primera falla (és a dir, si el seu ERRORLEVEL és diferent de zero). L'exemple anterior es pot condensar a:
Forma compacta: copy blah ..\test || exit /b %errorlevel%
Amb aquesta única línia s'expressa exactament la mateixa intenció: si la còpia no té èxit, sortir de l'script retornant l'error. És més compacte, fàcil de llegir i, en general, més elegant. La contrapart positiva de l'operador és &&, que executa la segona ordre només si la primera té èxit.
Els qui usen scripts batch diàriament solen preferir la variant amb || per claredat, llevat que necessitin compatibilitat amb versions de CMD molt antigues o entorns sense extensions. A la pràctica, en sistemes moderns de Windows aquest operador funciona sense problema i simplifica enormement el maneig derrors.
Finestres que es tanquen de cop: com diagnosticar i evitar-ho
Un problema molt comú en executar fitxers .bat és que en fer doble clic s'obre una consola, s'executa una cosa molt ràpida i la finestra es tanca, sense deixar temps a veure què ha passat. De vegades ni tan sols s'arriba a executar correctament el contingut del fitxer per lots.
Molts usuaris intenten solucionar-ho usant PAUSE o CMD /K, però no sempre serveix, sobretot si l'script conté errors de sintaxi greus, rutes incorrectes o errors en ordres primerencs. A Windows 11 (i versions similars), algunes errades fan que CMD acabi immediatament sense mostrar missatges clars.
Per depurar aquests casos és recomanable obrir una consola manualment (Win+R → cmd) i des d'aquí llançar el fitxer .bat escrivint la ruta. D'aquesta manera, encara que l'script falli, la consola continuarà oberta i podreu llegir qualsevol missatge d'error, sortida de diagnòstic o fins i tot afegir línies echo per a traces internes.
Una altra bona pràctica és activar ECHO al principi del script mentre depures (@echo on) i desactivar-lo després de solucionats els problemes (@echo off). Això us permet veure quines ordres s'estan executant realment, en quin ordre i amb quins paràmetres.
Maneig d'errors avançats: patrons pràctics
Més enllà de l'ús directe d'ERRORLEVEL després de cada ordre, hi ha patrons recurrents que ajuden a fer el codi més llegible i robust. Alguns exemples:
- Encadenat de comandes amb && i ||:
comando1 && comando2 || comando3per expressar "si ordre1 va bé, executa ordre2; si falla, executa ordre3". - Funcions etiquetades amb EXIT/B: subrutines tipus
call :MiFuncionque tornen codis d'error concrets, comprovats després ambif errorlevel. - Inicialització explícita d'ERRORLEVEL abans de seccions crítiques, per no arrossegar errors antics.
També es pot centralitzar el tractament derrors tenint una etiqueta comuna, per exemple :ErrorFatal, a la qual se salta mitjançant goto o call quan alguna cosa surt malament, mostrant missatges clars i tancant recursos si cal (arxius temporals, canvis de directori, etc.).
En tot cas, la decisió entre fer servir IF ERRORLEVEL o l'operador || depèn molt de l'estil personal i del nivell de compatibilitat que cerques. A la majoria d'escenaris actuals, la forma amb || no només és vàlida, sinó desitjable per claredat.
Expansió retardada i rendiment en scripts complexos
Quan es treballa amb estructures complexes, com ara jocs o interfícies “gràfiques” en consola (per exemple, un Buscamines en batch), l'expansió retardada esdevé imprescindible. En aquests casos es fan servir matrius simulades amb variables de l'estil b, i cal actualitzar i mostrar l'estat en bucles molt seguits.
Un exemple típic en un joc de buscamines implementat en batch seria recórrer el tauler i construir files amb informació de cada cel·la. El preprocessament de files podria veure's una cosa així (adaptat al que se sol fer servir):
fragment: for /l %%g in (0,1,!width!) do (
set "row=!row!!b!!d!"
)
for %%g in ("!widthx!") do (
set "row=!row!!b!"
)
Aquí s'aprofita l'expansió retardada (les exclamacions !row!, !b!, etc.) per anar concatenant contingut dinàmic a una variable que representa una fila de tauler. Sense delayed expansion seria impossible construir aquestes cadenes correctament dins del bucle.
El problema que sol aparèixer en taulers grans és el rendiment: si cada actualització implica centenars d'ordres set, la consola es torna notablement lenta. Alguns usuaris intenten “preprocessar” les files en variables i després bolcar-ho tot de cop, però es troben que la sortida s'interpreta com a text pla en lloc de “codi executable”.
Aquest punt és clau: CMD no avalua el contingut d'una variable com si fos un script nou tret que es faci servir alguna tècnica indirecta (per exemple, escriure'l a un fitxer .bat i després trucar-lo amb call), de manera que intentar que una variable amb “codi” s'executi directament no funciona com s'esperaria en altres llenguatges.
Una estratègia addicional per millorar el rendiment consisteix a minimitzar operacions que afectin el parseu complex (com moltes referències de delayed expansion dins de bucles profunds), i en el seu lloc precalcular parts estàtiques o semi-estàtiques fora dels bucles crítics. Tot i això, dins de les limitacions de CMD, un Buscamines amb centenars de cel·les sempre tindrà certa penalització.
Exemple de funció de visualització de tauler amb delayed expansion
Una funció de dibuix de tauler en un Buscamines en batch podeu incloure diverses capes de lògica: reposicionar el cursor, marcar temporalment la casella seleccionada, construir la representació línia a línia i després restaurar els valors originals. Un exemple aproximat podria ser:
Rutina aproximada: :board
echo %esc%==]"
set "board="
for /l %%g in (0,1,!height!) do (
set "board=!board!!row!!lf!"
)
echo !board!
set "b= "
set "b= "
exit /b
En aquesta rutina es fa el següent: es mou el cursor a la cantonada superior esquerra (usant una seqüència d'escapament emmagatzemada a %esc%), es calculen índexs auxiliars (temp_var), es marquen delimitadors visuals a la matriu b, es construeix la cadena board concatenant files preprocessades i salts de línia (!lf!), s'imprimeix tot de cop i després es restauren les variables al seu estat original.
La pregunta que sol sorgir aquí és com aconseguir que el preprocessament de files no només generi text, sinó que s'interpreti com a ordres o s'actualitzi el tauler de forma eficient. A CMD, el contingut de les variables no es reavalua automàticament com a codi, de manera que la solució passa per canviar l'enfocament: reduir el nombre de set y echo per actualització, i agrupar la sortida tant com sigui possible, com fa el patró anterior amb la variable board.
Una estratègia addicional per millorar el rendiment consisteix a minimitzar operacions que afectin el parseu complex (com moltes referències de delayed expansion dins de bucles profunds), i en el seu lloc precalcular parts estàtiques o semi-estàtiques fora dels bucles crítics. Tot i això, dins de les limitacions de CMD, un Buscamines amb centenars de cel·les sempre tindrà certa penalització.
Errors de processament i caràcters especials
A scripts extensos, un altre front de problemes habituals són els caràcters especials: parèntesis, redireccions, cometes, signes d'exclamació, etc. i problemes de codificació. Quan s'usen delayed expansion i bucles imbricats, aquests caràcters poden trencar el parseig de l'ordre si no s'escapen correctament.
Per exemple, un parèntesi de tancament inesperat pot provocar errors tipus “This command is not supported” o simplement avortar l'execució del bloc. Per evitar això, cal tenir molta cura en construir línies amb echo que contenen parèntesis o símbols de l'intèrpret d'ordres, i recolzar-se en tècniques com echo( o la duplicació de certs caràcters per a la seva fuita.
En documents especialitzats sobre batch avançat se solen incloure taules de “caràcters especials” i notes sobre com escapen en diferents contextos (dins de FOR, en blocs amb parèntesis, amb delayed expansion activa, etc.). Encara que no entrem al detall de cadascú aquí, convé recordar que com més complex sigui l'script, més val la pena provar-ho pas a pas i revisar meticulosament com es manegen aquests símbols.
També és freqüent trobar tècniques molt elaborades que combinen CMD amb altres llenguatges o eines (com VBScript o PowerShell) escrivint petits fragments a arxius temporals i executant-los, aprofitant el millor de cada entorn. En aquests casos, la cura amb els caràcters especials i les redireccions es torna encara més important.
Funcions, subrutines i estructures avançades en batch
El món del batch avançat no es limita a ordres soltes: hi ha tot un ecosistema de patrons per construir funcions reutilitzables, simular arrays, manejar arguments i tornar resultats. El més habitual és fer servir etiquetes (:MiFuncion) I la comanda call i crear menús interactius:
Exemple: @echo off
call :FunctionX
rem Más código aquí
exit /b 0
:FunctionX
rem Maneig d'errors dins de la funció
rem …
exit /b 0
Les subrutines en batch permeten encapsular lògica complexa, entre altres coses, convertir fragments repetitius (com ara comprovacions d'error, manipulació de cadenes o fitxers) en blocs cridables. Mitjançant exit /b es pot tornar un ERRORLEVEL concret al cridador, que després es controla amb if errorlevel o amb operadors tipus ||.
Hi ha tècniques encara més avançades on s'usen fluxos alternatius de dades (ADS, Alternate Data Streams) per emmagatzemar codi auxiliar associat al propi fitxer .bat, o es barregen seccions en altres llenguatges com VBScript dins del mateix fitxer. Aquests trucs permeten ampliar les capacitats del batch, però també compliquen el manteniment i la depuració, per la qual cosa solen reservar-se per a escenaris molt específics.
A molts manuals extensos de batch scripting es tracten a més temes com a generació d'arxius dinàmicament, ús de pushd y popd per gestionar directoris de forma segura, manipulació d'arguments (%1, %2, etc.), i diferències subtils entre .BAT i .CMD. Tot això es beneficia enormement dun bon control dentorn amb SETLOCAL/ ENDLOCAL i un maneig derrors sistemàtic.
dominar delayed expansion, La gestió de ERRORLEVEL i l'ús estratègic de SETLOCAL és el que separa els scripts per lots “de caminar per casa” dels que realment es poden utilitzar per a automatitzacions complexes i fiables, ja sigui per a eines internes, utilitats de sistema o fins i tot petits jocs i experiments en consola.
Redactor apassionat del món dels bytes i la tecnologia en general. M'encanta compartir els meus coneixements a través de l'escriptura, i això és el que faré en aquest bloc, mostrar tot el més interessant sobre gadgets, programari, maquinari, tendències tecnològiques, i més. El meu objectiu és ajudar-te a navegar pel món digital de forma senzilla i entretinguda.
