¿Cómo cambiar un parámetro y lanzarlo por completo desde args ls?

¿Cómo cambiar un parámetro y lanzarlo por completo desde args ls?

Tengo un script que obtiene N parámetros. Primero los analiza (extrae un valor específico X), luego llama a otro programa con dicho valor:

function main() {
    parse "$@"
    run "$@"
}
main "$@"

Quiero agregar un parámetro opcional al comienzo de la lista de argumentos (parámetro para configurar la versión de Python que estoy ejecutando). Entonces agregué esto a la función de análisis:

if [ "$1" = '2' ] || [ "$1" = '3' ]; then version=$1 && shift; else version=2; fi

Sin embargo, una vez finalizado el análisis, estoy atascado porque shiftno afecta la función de ejecución. ¿Cómo puedo hacer esto sin verificar nuevamente el valor del primer valor (lo que anularía el propósito de tener una función de análisis)?

Respuesta1

El alcance de cada función del shell (así como el alcance del código de nivel superior en el script) tiene su propiaparámetros posicionales, y solo puede acceder directamente al suyo. La solución más limpia es colocar los valores de los parámetros posicionales que le interesan.unformación. Luego puede leer y también modificar esa matriz en múltiples ámbitos de funciones.

Por ejemplo, podría hacer que este código aparezca cerca del comienzo de su secuencia de comandos:

declare -a args=("$@")
  • Nombra la matriz como quieras; no es necesario llamarla args.
  • Incluso puedes omitirlo declare -a, si lo deseas.
  • Realmente no es necesario que aparezca cerca del principio. Sólo tiene quecorrerantes de que se ejecute cualquier código al que se accede args. Incluso podría aparecer debajo de las definiciones de funciones de shell que utilizan args. Para mayor claridad, sugiero colocarlo cerca del principio.

Luego puede operar en la argsmatriz desde múltiples funciones. No es necesario pasarlo a las funciones; ya podrán acceder a él. Cuando el código en una función de shell modifica el contenido argsy luego regresa, el código de la persona que llama podrá observar los cambios.

Los parámetros posicionales en shells estilo Bourne, incluido Bash, utilizan indexación basada en 1. (Esto se debe a que $0, que se expande al nombre del programa, técnicamente no es un parámetro posicional y no cambia en los alcances de la función). Pero las matrices en Bash usan indexación basada en 0. Entonces, después args=("$@"), $1coincide ${args[0]}, $2coincide ${args[1]}, $3coincide ${args[2]}, etc. $@todavía coincide ${args[@]}como era de esperar.

Los escribí de esa manera, sin comillas, para facilitar la lectura. Por supuesto, casi siempre querrás poner entre comillas las expansiones que involucran tu argsmatriz, del mismo modo que casi siempre querrás poner entre comillas las expansiones que involucran parámetros posicionales.

Si decide seguir este enfoque, en lugar de:

shift

Escribirías:

args=("${args[@]:1}")

Si eres nuevo en el mundo de las matrices en Bash, querrás echar un vistazo ala parte relevante del manual de referencia de Bash. Quizás también quieras experimentar de forma interactiva. Por ejemplo:

ek@Cord:~$ args=('foo bar' 'baz quux' 'ham spam')
ek@Cord:~$ printf '[%s]\n' "${args[@]}"
[foo bar]
[baz quux]
[ham spam]
ek@Cord:~$ printf '[%s]\n' "${args[@]:1}"
[baz quux]
[ham spam]

El código correspondiente a

if [ "$1" = 2 ] || [ "$1" = 3 ]; then
    version="$1"
    shift
else
    version=2
fi

sería:

if [ "${args[0]}" = 2 ] || [ "${args[0]}" = 3 ]; then
    version="${args[0]}"
    args=("${args[@]:1}")
else
    version=2
fi

Usar una matriz es sintácticamente más engorroso, pero también más flexible.

Por otro lado, dado que parece tener la mayor parte del código de su script organizado en una runfunción y sus destinatarios de todos modos, podría considerar la alternativa de analizar cualquier argumento especial de la línea de comandos.antesllamando run, fuera de cualquier función de Shell, y luego llamando run "$@"como ya lo está haciendo.

Hay lenguajes de programación cuyas culturas asociadas tienen una fuerte ética de poner casi todo en funciones pequeñas (más o menos) autónomas. Bash no es ese lenguaje, y las formas limitadas de devolver datos complejos desde una función de shell es una de las razones. No debería tener miedo de escribir funciones de shell, e incluso debería estar dispuesto a escribir una gran cantidad de pequeñas funciones de shell. Pero no creo que debas preocuparte si resulta que la mejor forma para tu guión es otra.

Para obtener más información y algunas alternativas, incluido un enfoque extraño en el que se obtiene el resultado de la sustitución del proceso, consulteLa respuesta de Gilles.aParámetros posicionales de la persona que llama a la función.

información relacionada