🍎 AppleScript y JXA — Cheatsheet Completo 🍎
AppleScript es el lenguaje de automatización nativo de macOS desde 1993, con una sintaxis diseñada para parecerse al inglés natural y describir instrucciones hacia las aplicaciones del sistema. JavaScript for Automation (JXA) es la alternativa moderna introducida en OS X Yosemite (10.10), que permite usar JavaScript estándar como lenguaje de scripting del sistema en lugar de la sintaxis de AppleScript. Ambos lenguajes acceden al mismo framework de Open Scripting Architecture (OSA) de macOS y pueden automatizar prácticamente cualquier aplicación que soporte el diccionario AppleScript: Finder, Safari, Mail, Calendar, Notes, Numbers, Pages, Keynote, iTerm2, y miles de aplicaciones de terceros. Son fundamentales para crear flujos de trabajo de productividad avanzados, automatizar tareas repetitivas del sistema y orquestar la interacción entre múltiples aplicaciones de macOS.
1. 🌟 Conceptos Clave y Fundamentos
- Open Scripting Architecture (OSA): El framework de macOS que permite que las aplicaciones expongan su funcionalidad a lenguajes de scripting. Una app que soporta OSA tiene un “diccionario AppleScript”.
- Diccionario de la aplicación: La documentación de todos los objetos, comandos y propiedades que una app expone a AppleScript/JXA. Se consulta en Script Editor (Archivo → Abrir diccionario).
- Objeto de aplicación (
Application): El punto de entrada para interactuar con cualquier app. En AppleScript:tell application "Finder". En JXA:Application("Finder"). tellblock: En AppleScript, establece el contexto de la aplicación destino para los comandos del bloque.- System Events: Aplicación especial de macOS que permite controlar elementos de UI de cualquier aplicación, incluso las que no tienen diccionario AppleScript propio.
do shell script: Comando de AppleScript para ejecutar comandos Bash/Zsh y capturar su salida como string. El puente entre AppleScript y el shell Unix.- Script Editor: La IDE nativa de macOS para editar y ejecutar scripts AppleScript y JXA (en Applications → Utilities).
- osascript: Herramienta de línea de comandos para ejecutar scripts AppleScript y JXA directamente desde Terminal.
- Automation: En JXA, el objeto global que da acceso a las funcionalidades de automatización equivalentes a AppleScript.
- Accessibility Inspector: Herramienta de macOS para inspeccionar la jerarquía de accesibilidad de cualquier aplicación (útil para System Events UI scripting).
2.
Herramientas y Entorno
2.1. Script Editor y osascript
# Ejecutar AppleScript desde Terminal
osascript -e 'tell application "Finder" to activate'
osascript mi_script.applescript
# Ejecutar JXA desde Terminal
osascript -l JavaScript -e 'Application("Finder").activate()'
osascript -l JavaScript mi_script.js
# Mostrar notificación desde Terminal
osascript -e 'display notification "Deploy completado" with title "CI/CD" sound name "Glass"'
# Ejecutar con shebang (AppleScript)
#!/usr/bin/osascript
tell application "Finder" to activate
# Ejecutar con shebang (JXA)
#!/usr/bin/osascript -l JavaScript
Application("Finder").activate()
# chmod +x script.applescript && ./script.applescript
2.2. Estructura Básica de un Script
-- AppleScript: comentarios con --
(*
Comentario
multilínea
*)
-- Variables en AppleScript
set miVariable to "valor"
set numero to 42
set lista to {1, 2, 3, "cuatro"}
set registroHash to {nombre:"Ana", edad:28}
-- Mostrar resultado
return "valor de retorno"
// JXA: sintaxis JavaScript estándar
// Comentarios normales de JS
// OJO: No todas las APIs de Node.js están disponibles en JXA
// JXA es JavaScript del motor JavaScriptCore, no Node.js
const app = Application.currentApplication();
app.includeStandardAdditions = true; // Habilitar comandos estándar
// Variables normales de JavaScript
const nombre = "JXA";
let contador = 0;
const lista = [1, 2, 3, "cuatro"];
3. 🗣️ AppleScript — Sintaxis Fundamental
-- ===== VARIABLES =====
set nombre to "macOS"
set version to 14.0
set activo to true
set nada to missing value -- Equivalente a null/nil
-- ===== STRINGS =====
set saludo to "Hola, " & nombre & "!" -- Concatenación con &
set longitud to length of saludo -- Longitud del string
set mayusculas to (name of (info for
"POSIX
~")) -- (ejemplo)
-- ===== LISTAS (Arrays) =====
set frutas to {"manzana", "pera", "uva", "kiwi"}
set primera to item 1 of frutas -- "manzana" (índice 1-based)
set ultima to last item of frutas -- "kiwi"
set mitad to items 2 thru 3 of frutas -- {"pera", "uva"}
set cuenta to count of frutas -- 4
set nuevaLista to frutas & {"mango"} -- Agregar elemento (crea nueva lista)
-- ===== REGISTROS (Objetos/Diccionarios) =====
set persona to {nombre:"Luis", edad:30, activo:true}
set nom to nombre of persona -- "Luis"
set e to edad of persona -- 30
-- ===== OPERADORES =====
-- Comparación
5 = 5 -- true (igual)
5 ≠ 4 -- true (distinto) o: 5 is not 4
10 > 5 -- true
10 ≥ 10 -- true (mayor o igual)
"abc" comes before "xyz" -- true (comparación de strings)
"abc" contains "b" -- true
-- Lógicos
true and false -- false
true or false -- true
not true -- false
-- ===== CONDICIONALES =====
set temperatura to 25
if temperatura > 35 then
display dialog "Peligroso"
else if temperatura > 25 then
display dialog "Caluroso"
else if temperatura > 15 then
display dialog "Agradable"
else
display dialog "Frío"
end if
-- ===== BUCLES =====
-- repeat ... times
repeat 3 times
say "Hola"
end repeat
-- repeat with (for each)
repeat with fruta in frutas
log fruta -- Imprime en la consola de Script Editor
end repeat
-- repeat with (rango numérico)
repeat with i from 1 to 10 by 2
log i -- 1, 3, 5, 7, 9
end repeat
-- repeat while
set contador to 0
repeat while contador < 5
set contador to contador + 1
end repeat
-- ===== FUNCIONES (Handlers) =====
on saludar(nombre)
return "Hola, " & nombre & "!"
end saludar
set resultado to saludar("AppleScript")
display dialog resultado
4. 🔗 Tell Blocks — Controlando Aplicaciones
-- ===== ESTRUCTURA BÁSICA DEL TELL BLOCK =====
tell application "NombreAplicación"
-- Comandos enviados a la aplicación
activate -- Traer al frente
end tell
-- Tell anidado
tell application "Finder"
tell window 1
set current view to icon view
end tell
end tell
-- ===== FINDER =====
tell application "Finder"
activate
-- Obtener carpeta actual del Finder
set carpetaActual to target of front Finder window
-- Abrir archivo o carpeta
open POSIX
"/Users/usuario/Documentos"
-- Obtener archivos del escritorio
set archivosEscritorio to every
of desktop
set cantidadArchivos to count of archivosEscritorio
-- Crear carpeta nueva
make new folder at desktop with properties {name:"Mi Nueva Carpeta"}
-- Duplicar archivo
duplicate
"informe.pdf" of desktop to folder "Backup" of desktop
-- Mover a la Papelera
move
"temporal.txt" of desktop to trash
-- Vaciar papelera
empty trash
-- Obtener ruta POSIX de un elemento
set posixRuta to POSIX path of (desktop as alias)
end tell
-- ===== SAFARI =====
tell application "Safari"
activate
-- Abrir URL en pestaña actual
open location "https://developer.apple.com"
-- Obtener URL de la pestaña activa
set urlActual to URL of current tab of window 1
-- Obtener título de la página
set tituloActual to name of current tab of window 1
-- Abrir nueva pestaña
tell window 1
set newTab to make new tab
set current tab to newTab
open location "https://applescript.net" in newTab
end tell
-- Ejecutar JavaScript en la página
do JavaScript "document.title" in current tab of window 1
end tell
-- ===== MAIL =====
tell application "Mail"
-- Crear y enviar email
set nuevoMensaje to make new outgoing message with properties {
subject: "Reporte Automático",
content: "Adjunto el reporte diario generado automáticamente.",
visible: true
}
tell nuevoMensaje
make new to recipient with properties {
name: "Destinatario",
address: "destino@empresa.com"
}
make new attachment with properties {
name: (POSIX
"/tmp/reporte.pdf")
}
end tell
send nuevoMensaje
end tell
5. 🖥️ System Events — Automatización de UI
System Events es el puente para controlar la UI de aplicaciones que no tienen diccionario AppleScript propio.
-- Requerido: Habilitar "Accessibility" para Script Editor en:
-- Ajustes del Sistema → Privacidad y Seguridad → Accesibilidad
tell application "System Events"
-- ===== PROCESOS =====
-- Obtener proceso de aplicación activa
set procesoActivo to first application process whose frontmost is true
set nombreApp to name of procesoActivo
-- Enviar teclas (keystroke)
tell process "Finder"
keystroke "q" using command down -- Cmd+Q (Salir)
keystroke "n" using {command down} -- Cmd+N
key code 36 -- Return (por código de tecla)
key code 48 using shift down -- Shift+Tab
end tell
-- ===== CONTROLES DE UI =====
tell application process "TextEdit"
-- Navegar jerarquía de UI
set ventana to window "Untitled"
set area to scroll area 1 of ventana
set texto to text area 1 of area
-- Hacer clic en un botón
click button "OK" of ventana
-- Establecer valor de un campo
set value of text field 1 of ventana to "Nuevo texto"
-- Seleccionar item de menú
click menu item "Save..." of menu "File" of menu bar 1
-- Obtener todos los elementos de UI
set elementos to UI elements of ventana
end tell
-- ===== MENÚS =====
tell application process "Finder"
-- Seleccionar comando de menú por nombre
click menu item "Get Info" of menu "File" of menu bar 1
-- Navegar submenús
click menu item "Services" of menu "Finder" of menu bar 1
-- Luego click en el submenú
end tell
-- ===== CLIC EN COORDENADAS =====
click at {500, 300} -- Clic en posición absoluta de pantalla
-- ===== ARRASTRAR =====
drag from {100, 200} to {500, 200}
end tell
6. 🐚 do shell script — Puente con el Terminal
-- Ejecutar comando Bash y capturar salida
set salida to do shell script "ls -la ~/Desktop"
display dialog salida
-- Con variables
set directorio to POSIX path of (path to desktop)
set archivos to do shell script "find " & quoted form of directorio & " -name '*.pdf'"
-- Como administrador (requiere contraseña de usuario)
do shell script "softwareupdate -l" with administrator privileges
-- Convertir ruta HFS+ de macOS a POSIX
set rutaHFS to (path to desktop folder) as text -- "Macintosh HD:Users:usuario:Desktop:"
set rutaPOSIX to POSIX path of rutaHFS -- "/Users/usuario/Desktop/"
-- Y a la inversa
set archivoAlias to (POSIX
"/Users/usuario/Desktop/doc.pdf") as alias
-- Ejemplos prácticos
-- Obtener fecha en formato ISO
set fecha to do shell script "date +%Y-%m-%d"
-- Obtener IP local
set ip to do shell script "ipconfig getifaddr en0"
-- Verificar si un proceso está corriendo
set estaEjecutando to do shell script "pgrep -x 'Docker' > /dev/null 2>&1 && echo 'si' || echo 'no'"
-- Ejecutar script Python
set resultado to do shell script "python3 ~/scripts/procesar.py"
-- Git operations
do shell script "cd ~/proyecto && git pull --rebase"
-- Subir notificación via terminal tool
do shell script "terminal-notifier -title 'Script' -message 'Completado'"
7. ⚡ JXA — JavaScript for Automation
// ===== CONFIGURACIÓN INICIAL =====
const app = Application.currentApplication();
app.includeStandardAdditions = true; // Habilitar displayDialog, say, etc.
// ===== DIALÓGOS =====
app.displayDialog("Hola desde JXA!", {
defaultAnswer: "Mundo",
buttons: ["Cancelar", "OK"],
defaultButton: "OK"
});
const respuesta = app.displayDialog("¿Cómo te llamas?", {
defaultAnswer: "",
buttons: ["Cancelar", "OK"],
defaultButton: "OK"
});
const nombre = respuesta.textReturned;
app.displayAlert(`Hola, ${nombre}!`);
// ===== NOTIFICACIONES =====
app.displayNotification("Proceso completado", {
withTitle: "Mi Script",
subtitle: "Éxito",
soundName: "Glass"
});
// ===== FINDER =====
const Finder = Application("Finder");
Finder.activate();
// Obtener archivos del escritorio
const archivos = Finder.desktop.
s();
archivos.forEach(archivo => {
console.log(archivo.name());
});
// Abrir carpeta
Finder.open(Path("/Users/usuario/Documentos"));
// Crear carpeta
Finder.make({
new: "folder",
at: Finder.desktop(),
withProperties: { name: "Nueva Carpeta" }
});
// ===== SAFARI =====
const Safari = Application("Safari");
Safari.activate();
// Obtener URL actual
const url = Safari.windows[0].currentTab.url();
console.log(url);
// Abrir nueva pestaña
Safari.windows[0].make({ new: "tab" });
Safari.windows[0].currentTab.url = "https://developer.apple.com";
// Ejecutar JS en la página
const titulo = Safari.doJavaScript("document.title", {
in: Safari.windows[0].currentTab()
});
// ===== SHELL COMMANDS =====
app.doShellScript("ls ~/Desktop");
const ip = app.doShellScript("ipconfig getifaddr en0");
console.log("IP:", ip);
// ===== SYSTEM EVENTS (JXA) =====
const SE = Application("System Events");
// Keystroke
const proceso = SE.applicationProcesses.byName("Finder");
proceso.keyDown({ using: "command down" }); // Mantener Cmd
proceso.keystroke("n"); // Cmd+N
proceso.keyUp({ using: "command down" });
// Click en elemento UI
const ventana = proceso.windows[0];
ventana.buttons.byName("OK").click();
// ===== SCRIPT DE AUTOMATIZACIÓN COMPLETO =====
function procesarDocumentos() {
const Finder = Application("Finder");
const app = Application.currentApplication();
app.includeStandardAdditions = true;
// Seleccionar carpeta
const carpetaSeleccionada = app.chooseFolder({
withPrompt: "Selecciona la carpeta con documentos PDF"
});
// Obtener todos los PDFs
const carpeta = Finder.folders[carpetaSeleccionada.toString()];
const pdfs = carpeta.
s().filter(f => f.name().endsWith(".pdf"));
app.displayDialog(`Encontrados ${pdfs.length} PDFs. ¿Procesar?`, {
buttons: ["Cancelar", "Procesar"],
defaultButton: "Procesar"
});
pdfs.forEach((pdf, i) => {
// Notificar progreso
app.displayNotification(`Procesando ${i + 1}/${pdfs.length}: ${pdf.name()}`, {
withTitle: "Procesador PDF"
});
// Ejecutar script de conversión
app.doShellScript(`python3 ~/scripts/convertir_pdf.py "${pdf.posixPath()}"`);
});
app.displayAlert("Procesamiento completado!");
}
procesarDocumentos();
8. 📱 Aplicaciones de Productividad Populares
-- ===== CALENDAR (iCal) =====
tell application "Calendar"
-- Crear evento
tell calendar "Trabajo"
make new event with properties {
summary: "Reunión de equipo",
start date: date "Tuesday, January 14, 2025 at 10:00:00 AM",
end date: date "Tuesday, January 14, 2025 at 11:00:00 AM",
location: "Sala A"
}
end tell
-- Obtener eventos del día
set hoy to current date
set events of today to every event of calendar "Trabajo" whose start date ≥ hoy
end tell
-- ===== NOTES =====
tell application "Notes"
-- Crear nota
make new note at folder "General" of account "iCloud" with properties {
name: "Ideas de automatización",
body: "<div>Lista de tareas pendientes:</div><ul><li>Automatizar reportes</li></ul>"
}
-- Obtener todas las notas
set misNotas to every note
repeat with nota in misNotas
log name of nota
end repeat
end tell
-- ===== MESSAGES (iMessage/SMS) =====
tell application "Messages"
-- Enviar mensaje (requiere permisos)
set destinatario to buddy "+34600000000" of (first service whose service type is iMessage)
send "Hola, esto es un mensaje automático." to destinatario
end tell
-- ===== KEYNOTE =====
tell application "Keynote"
-- Abrir presentación
open POSIX
"/Users/usuario/presentacion.key"
tell front document
-- Exportar a PDF
export to POSIX
"/Users/usuario/presentacion.pdf" as PDF
-- Obtener número de diapositivas
set numSlides to count of slides
end tell
end tell
-- ===== NUMBERS =====
tell application "Numbers"
open POSIX
"/Users/usuario/datos.numbers"
tell front document
tell sheet 1
tell table 1
-- Leer valor de celda
set valor to value of cell "B2"
-- Escribir valor en celda
set value of cell "C2" to valor * 1.21 -- Calcular con IVA
end tell
end tell
end tell
save front document
end tell
9. 🔔 Notificaciones y Diálogos
-- ===== DISPLAY DIALOG =====
-- Diálogo simple
display dialog "¿Deseas continuar?"
-- Con botones personalizados
set respuesta to display dialog "¿Guardar cambios?" buttons {"No guardar", "Cancelar", "Guardar"} default button "Guardar"
set botonPresionado to button returned of respuesta
-- Con campo de texto
set entrada to display dialog "Introduce tu nombre:" default answer "Usuario" with title "Identificación"
set nombre to text returned of entrada
-- Con icono
display dialog "Error crítico detectado." with icon stop
display dialog "Advertencia." with icon caution
display dialog "Información." with icon note
-- ===== DISPLAY ALERT =====
display alert "Alerta de Sistema" message "El disco está casi lleno." as critical
-- ===== NOTIFICACIÓN DEL SISTEMA =====
display notification "El backup completó con éxito" with title "Backup Manager" subtitle "15 archivos copiados" sound name "Glass"
-- ===== CHOOSE FROM LIST =====
set opcion to choose from list {"Opción A", "Opción B", "Opción C"} with title "Selección" with prompt "Elige una opción:"
if opcion is false then error "Cancelado"
set opcionElegida to item 1 of opcion
-- ===== CHOOSE FILE / FOLDER =====
set archivoElegido to choose
with prompt "Selecciona el archivo a procesar:" of type {"pdf", "docx"}
set carpetaElegida to choose folder with prompt "Selecciona la carpeta destino:"
-- ===== VOZ (Text to Speech) =====
say "El proceso ha finalizado exitosamente"
say "Error en el sistema" using "Alex" speaking rate 150 pitch 50
10. ⚠️ Errores Comunes y Pitfalls
-
Permisos de Accesibilidad: El UI scripting con
System Eventsrequiere que la app (Script Editor, Terminal, etc.) tenga permisos de Accesibilidad en Ajustes del Sistema → Privacidad y Seguridad → Accesibilidad. Sin esto, los scripts fallan silenciosamente o lanzan errores de permisos. -
Rutas HFS+ vs POSIX: AppleScript usa rutas HFS+ (
"Macintosh HD:Users:usuario:") internamente, pero la mayoría de comandos del shell y las APIs modernas usan rutas POSIX ("/Users/usuario/"). UsaPOSIX path ofyPOSIXpara convertir entre formatos.
-
Bloqueo de UI durante ejecución:
display dialogbloquea el hilo principal. Para scripts largos, considera ejecutar conosascriptdesde Terminal en segundo plano o usar JXA con callbacks. -
Versiones de macOS: Las APIs de AppleScript cambian entre versiones de macOS. Un script que funciona en Ventura puede fallar en Sequoia si Apple modifica los diccionarios de las apps.
-
tell applicationactiva la app:tell application "Finder"puede traer Finder al frente si no está activo. Usatell application "Finder" to set la_ruta to (POSIX path of desktop)sin activar explícitamente si no lo necesitas. -
Strings multilínea en AppleScript: Para insertar un salto de línea en AppleScript, usa el carácter
returnolinefeed:set texto to "Línea 1" & return & "Línea 2". -
JXA: No es Node.js: JXA usa JavaScriptCore (el motor de Safari/WebKit), no V8/Node.js. No puedes usar
require,import,fetchnativo, ni módulos npm. El ámbito de APIs disponibles es limitado al framework OSA.
11.
Buenas Prácticas y Consejos Pro
-
Consulta el diccionario de cada app: Script Editor → Archivo → Abrir diccionario. Es la documentación oficial de lo que cada aplicación expone a AppleScript. Es tu mejor herramienta de referencia.
-
Usa
try...on error...end trypara manejar errores:try tell application "Finder" to open folder "carpeta_inexistente" on error mensaje número numeroError display dialog "Error " & numeroError & ": " & mensaje end try -
JXA para lógica compleja, AppleScript para interacción con apps: JXA es más potente para lógica de programación compleja (arrays, objetos, funciones). AppleScript suele ser más readable para comandos de aplicaciones.
-
Combina con
do shell script: Para operaciones donde ni AppleScript ni JXA son suficientes, delega a scripts Bash, Python o cualquier herramienta de línea de comandos. -
Automator como alternativa visual: Para workflows simples, Automator (también nativo en macOS) puede ser más rápido. Puede embeber AppleScript/JXA como pasos dentro de workflows visuales.
-
Shortcuts.app (macOS 13+): La aplicación Atajos de teclado de iOS llega a macOS y puede ejecutar AppleScript. Considera Shortcuts para automatizaciones que requieren integración con Siri o menu bar.
-
logpara debugging en Script Editor: En Script Editor,log "mensaje de debug"imprime en el panel de mensajes (no lanza diálogos). Equivale aconsole.logpara debugging sin interrumpir el flujo.
Este cheatsheet proporciona una referencia exhaustiva de AppleScript y JavaScript for Automation (JXA), cubriendo desde la sintaxis fundamental de ambos lenguajes, la interacción con aplicaciones nativas de macOS (Finder, Safari, Mail, Calendar, Notes, Numbers, Keynote), el poderoso UI scripting con System Events, el puente hacia el shell Unix con do shell script, el sistema de diálogos y notificaciones, hasta las mejores prácticas para crear scripts de automatización robustos y mantenibles en el ecosistema macOS.