Un programa de terminal recibe sus datos como argumentos: el archivo que tiene que leer, cuántas líneas mostrar, si debe dar detalle. En Kotlin llegan en el parámetro args de main. Aquí verás cómo leerlos sin que el programa reviente, cómo interpretar opciones como --limite 5 y cómo terminar con el código de salida correcto.
También te puede interesar
args: lo que escribiste después del programa
En Kotlin, main puede recibir un parámetro args: Array<String>. Ahí llega cada palabra que escribiste después del nombre del programa, ya separada por la terminal, sin el nombre del programa (al revés que en C o en Python, donde el primero es el propio programa):
fun main(args: Array<String>) {
println("Recibí ${args.size} argumentos")
for ((i, arg) in args.withIndex()) {
println(" args[$i] = $arg")
}
}Para probarlo hay que compilar a un .jar con el runtime de Kotlin dentro y ejecutarlo con java:
kotlinc basico.kt -include-runtime -d basico.jar
salida$ java -jar basico.jar ventas.csv --limite 5 Recibí 3 argumentos args[0] = ventas.csv args[1] = --limite args[2] = 5 $ java -jar basico.jar "mi archivo.csv" -v Recibí 2 argumentos args[0] = mi archivo.csv args[1] = -v $ java -jar basico.jar Recibí 0 argumentos
Fíjate en dos cosas. Las comillas las quita la terminal: "mi archivo.csv" llega como un solo argumento, con su espacio. Y --limite no tiene nada de especial: para Kotlin es un texto más. Interpretar las opciones es trabajo tuyo, o de una biblioteca.
Si tu programa no usa argumentos, escribe fun main() sin parámetros: las dos formas son válidas.
El error de siempre: pedir un argumento que no llegó
fun main(args: Array<String>) {
val archivo = args[0]
println("Procesando $archivo")
}salidaException in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 0 out of bounds for length 0
at PrimeroKt.main(primero.kt:2)args es un Array de Java por debajo, y leer una posición que no existe lanza ArrayIndexOutOfBoundsException, con una traza que al usuario no le dice nada. La forma idiomática es firstOrNull() (o getOrNull(1) para el segundo), que devuelve null si no hay, y el operador Elvis ?: para decidir qué hacer en ese caso:
import kotlin.system.exitProcess
fun main(args: Array<String>) {
val archivo = args.firstOrNull() ?: run {
System.err.println("Uso: resumen ARCHIVO")
exitProcess(2)
}
println("Procesando $archivo")
}salidaUso: resumen ARCHIVO (código de salida: 2)
exitProcess(2), de kotlin.system, termina el programa con ese código de salida. La convención de las herramientas de Unix es 0 si todo fue bien, 1 para fallos generales y 2 para un uso incorrecto; los scripts de shell y las tareas de CI lo leen con $?. El mensaje de error va a System.err, no a la salida normal, para que no se mezcle con los datos si alguien redirige la salida a un archivo.
Opciones con nombre, a mano
Este es un programa completo con el estilo habitual de las herramientas de Unix: opciones cortas y largas (-n y --limite), una que lleva valor, una ayuda y mensajes claros cuando algo falla. Muestra las primeras líneas de un archivo:
import java.io.File
import kotlin.system.exitProcess
data class Opciones(val archivo: String, val limite: Int = 10, val detalle: Boolean = false)
const val AYUDA = """Uso: resumen [opciones] ARCHIVO
Muestra las primeras líneas de ARCHIVO.
Opciones:
-n, --limite N cuántas líneas mostrar (10 por omisión)
-v, --detalle numera las líneas
-h, --ayuda muestra esta ayuda"""
fun fallar(mensaje: String): Nothing {
System.err.println("error: $mensaje")
System.err.println("Prueba con --ayuda.")
exitProcess(2)
}
fun leerOpciones(args: Array<String>): Opciones {
var archivo: String? = null
var limite = 10
var detalle = false
var i = 0
while (i < args.size) {
when (val a = args[i]) {
"-h", "--ayuda" -> {
println(AYUDA)
exitProcess(0)
}
"-v", "--detalle" -> detalle = true
"-n", "--limite" -> {
val valor = args.getOrNull(i + 1) ?: fallar("falta el número después de $a")
limite = valor.toIntOrNull()?.takeIf { it > 0 }
?: fallar("$a espera un número positivo, no «$valor»")
i++
}
else -> when {
a.startsWith("-") -> fallar("opción desconocida: $a")
archivo == null -> archivo = a
else -> fallar("sobra el argumento: $a")
}
}
i++
}
return Opciones(archivo ?: fallar("falta el ARCHIVO"), limite, detalle)
}
fun main(args: Array<String>) {
val op = leerOpciones(args)
val archivo = File(op.archivo)
if (!archivo.isFile) fallar("no existe el archivo ${op.archivo}")
archivo.useLines { lineas ->
lineas.take(op.limite).forEachIndexed { n, linea ->
println(if (op.detalle) "${n + 1}: $linea" else linea)
}
}
}Lo ejecutamos varias veces, con usos correctos e incorrectos, mirando en cada caso el código de salida:
salida$ java -jar opciones.jar -n 3 -v ventas.csv 1: fecha,producto,cantidad 2: 2026-11-02,café,3 3: 2026-11-02,taza,2 (código de salida: 0) $ java -jar opciones.jar ventas.csv --limite 2 fecha,producto,cantidad 2026-11-02,café,3 (código de salida: 0) $ java -jar opciones.jar --ayuda Uso: resumen [opciones] ARCHIVO Muestra las primeras líneas de ARCHIVO. Opciones: -n, --limite N cuántas líneas mostrar (10 por omisión) -v, --detalle numera las líneas -h, --ayuda muestra esta ayuda (código de salida: 0) $ java -jar opciones.jar --limite tres ventas.csv error: --limite espera un número positivo, no «tres» Prueba con --ayuda. (código de salida: 2) $ java -jar opciones.jar ventas.csv --color error: opción desconocida: --color Prueba con --ayuda. (código de salida: 2) $ java -jar opciones.jar error: falta el ARCHIVO Prueba con --ayuda. (código de salida: 2) $ java -jar opciones.jar otro.csv error: no existe el archivo otro.csv Prueba con --ayuda. (código de salida: 2)
Tres detalles de Kotlin hacen corto el analizador:
fallar()devuelveNothing, el tipo de las funciones que nunca terminan con normalidad. Por eso se puede escribir a la derecha de?:: el compilador sabe que, si se llega ahí, el programa no sigue, y quevalorya no puede sernull.when (val a = args[i])declara la variable dentro del propiowhen, y una rama puede tener varios valores separados por comas.toIntOrNull()?.takeIf { it > 0 }convierte y valida en una línea: devuelvenullsi el texto no es un número o si no es positivo.
Si vienes de Java: lo mismo, con menos ceremonia
En Java el parámetro es String[] args y la lógica sería igual, con Integer.parseInt dentro de un try y System.exit(2). Puedes compararlo con los argumentos de la línea de órdenes en Java.
¿Y una biblioteca?
Para una herramienta con subcomandos, opciones repetidas o autocompletado, el analizador a mano se queda corto. La biblioteca más usada en Kotlin es Clikt (com.github.ajalt.clikt:clikt, versión 5.1.0 en Maven Central al escribir esto), que genera la ayuda y los mensajes de error a partir de la declaración de las opciones. Para dos o tres opciones, lo de esta página basta y no añade dependencias.
Resumen
- ParaUsa
- Recibir los argumentos
fun main(args: Array<String>) - El primero, si lo hay
args.firstOrNull()oargs.getOrNull(0) - Un número
texto.toIntOrNull() ?: fallar(...) - Salir con un código
exitProcess(2), dekotlin.system - Mensajes de error
System.err.println(...) - Empaquetar y ejecutar
kotlinc x.kt -include-runtime -d x.jaryjava -jar x.jar ...
Todo el código de esta página se compiló con Kotlin 2.4.21 y se ejecutó en la JVM de Temurin 25.0.5 en un contenedor limpio y sin red antes de publicarla; las salidas y los mensajes del compilador están copiados de esa ejecución.