Parámetros Línea de Comandos. Go
SOLUCIONARIO
Parámetros Línea de Comandos. Go
2025-11-16
Por
Occam's Razor

package main

import "os"
import "fmt"

func main() {

    fmt.Println (len (os.Args[1:]), " Parameters...")

    /*argsWithProg := os.Args*/
    argsWithoutProg := os.Args[1:]
    
    for i, arg := range argsWithoutProg {
        fmt.Println ("Parameter ", i, ": ", arg)
        
    }
    if len(argsWithoutProg) != 1{
        fmt.Println ("Just one Parameter Please")
        os.Exit(-1)
    }
    fmt.Println ("Hello", argsWithoutProg[0])
}

Go nos ofrece todos los parámetros en una matriz de la que podremos extraer fácilmente toda la información que necesitamos, como por ejemplo, el número de parámetros.

Go como otros lenguajes almacena en la primera entrada de la matriz el nombre del programa que se ejecuta, sin embargo es muy sencillo obtener una matriz solo con los parámetros utilizando un slice del array.

Si bien, el valor de os.Args[0] contiene el nombre del programa que se está ejecutando, no podemos modificar este valor directamente para cambiar el nombre del proceso que aparece en ps.

SOY NOVATO

Es posible modificar el valor de os.Args[0] usando funciones no seguras del lenguaje, fundamentalmente obteniendo un puntero directamente al parámetro y modificándolo.. El siguiente código muestra un ejemplo de como hacerlo:

var name String
name = "Hello"
a0str := (*reflect.StringHeader)(unsafe.Pointer(&os.Args[0]))
argv0 := (*[1 << 30]byte)(unsafe.Pointer(a0str.Data))[:a0str.Len]

n := copy(argv0, name)
if n < len(argv0) {
  argv0[n] = 0
}

En mi sistema he tenido que sustituir el último if por un bucle que borra el resto de la cadena,

    for i:=n; i < argv0str.Len; i++ { argv0[i] =0 }

De lo contrario, después de la cadena Hello todavía podemos ver los restos del nombre original (asumiendo que el nombre original era más largo que Hello)

En Go, las cadenas son inmutables, es decir, una vez creadas no se pueden modificar, por esa razón, cuando modificamos os.Args[0], estamos asignando una nueva cadena a esa entrada del array, en lugar de sobreescribir el os.Args[0] original que contiene el nombre del programa conocido por el OS

Como sucede con la mayoría de los lenguajes más modernos, disponemos de numerosos paquetes para poder hacer casi de todo. En el caso concreto de procesar la línea de comandos, una de las opciones disponibles replica el comportamiento de la librería getopt de GNU, y es la opción recomendada cuando se quiera re-escribir alguna de las utilidades GNU estándar en Go.

Veamos un ejemplo de como usarlo:

package main

import (
       "os"
       "fmt"
       "github.com/pborman/getopt"
)

func main() {
    opt1 := getopt.StringLong ("input", 'i', "input.txt", "Fichero Entrada")
    opt2 := getopt.StringLong ("output", 'o', "output.txt", "Fichero Salida")
    optAyuda := getopt.BoolLong("help", 0, "Help")
    getopt.Parse()

    if *optAyuda {
        getopt.Usage()
        os.Exit(0)
    }

    fmt.Println ("Op1 :" + *opt1 + " Op2: " + *opt2)
}

El programa utiliza el módulo github.com/pborman/getopt. Si, Go nos permite usar módulos directamente de github. Disponemos de diferentes funciones para declarar distintos tipos de parámetros. En el ejemplo estamos declarando dos cadenas de caracteres y un valor booleano para el flag de ayuda. Las funciones de soporte nos permite indicar cual será el flag largo (usando --) y el corto (con un único -), además de un valor por defecto y lo que se mostrará al ejecutar la función Usage.

SOY NOVATO

Para poder usar un módulo externo en go tenemos que crear un fichero `go.mod` en el que se almacena la lista de dependencias de nuestro programa, así como sus versiones. Para poder compilar el programa anterior, primero debemos crear un fichero `go.mod`, lo que podemos hacer de la siguiente forma:
    # go mod init solucionario/cmdline-getopt
    go: creating new go.mod: module solucionario/cmdline-getopt
    go: to add module requirements and sums:
        go mod tidy
    root@624154d820aa:/opt/code/cmdline# go mod tidy
Donde le hemos dado el nombre `solucionario/cmdliune-getopt` a nuestro programa. Los comandos anteriores crearan un fichero `go.mod` como este:
    # cat go.mod
    module solucionario/cmdline-getopt

    go 1.19

    require github.com/pborman/getopt v1.1.0

Existen otros paquetes con los que procesar la línea de comandos y os animamos a que exploréis las posibilidades.

Resumen

  • Go recibe las opciones pasadas en la línea de comandos en la variable os.Args
  • La entrada 0 contiene el nombre del programa sin embargo, no puede ser modificada directamente
  • El paquete github.com/pborman/getopt ofrece la misma funcionaldiad que la librería getopt.

SOBRE Occam's Razor
Somos una revista libre que intenta explicar de forma sencilla conceptos tecnológicos y científicos de los que no podemos escapar. Al final, todo es más fácil de lo que parece!

 
Tu publicidad aquí :)