¿Cómo acceder a los argumentos de la línea de comandos de la persona que llama dentro de una función?

95

Estoy intentando escribir una función en bash que acceda a los argumentos de la línea de comandos de los scripts, pero se reemplazan con los argumentos posicionales de la función. ¿Hay alguna forma de que la función acceda a los argumentos de la línea de comando si no se pasan explícitamente?

# Demo function
function stuff {
  echo $0 $*
}

# Echo's the name of the script, but no command line arguments
stuff

# Echo's everything I want, but trying to avoid
stuff $*
DonGar
fuente
3
Estoy un poco confundido, ¿quieres los argumentos sin pasarlos?
Ravi Vyas
4
Sí, el punto es obtener también los argumentos de la línea de comandos desde dentro de una función sin pasarlos como argumentos funcionales. Tiene que ver con una situación de manejo de errores en la que quiero hacer un manejo de errores basado en argumentos de línea de comando independientemente de los argumentos pasados ​​a la función.
DonGar
Para su información, $*es extremadamente cochecito - que va a cambiar ./yourScript "first argument" "second argument"a ./yourscript "first" "argument" "second" "argument", o cambiar ./yourscript '*.txt'a algo así como ./yourscript one.txt two.txta pesar de las cotizaciones.
Charles Duffy

Respuestas:

46

Mi lectura del manual bash ref dice que estas cosas están capturadas en BASH_ARGV, aunque habla mucho de "la pila".

#!/bin/bash

function argv {
    for a in ${BASH_ARGV[*]} ; do
      echo -n "$a "
    done
    echo
}

function f {
    echo f $1 $2 $3
    echo -n f ; argv
}

function g {
    echo g $1 $2 $3
    echo -n g; argv
    f
}

f boo bar baz
g goo gar gaz

Guardar en f.sh

$ ./f.sh arg0 arg1 arg2
f boo bar baz
farg2 arg1 arg0 
g goo gar gaz
garg2 arg1 arg0 
f
farg2 arg1 arg0 
mcarifio
fuente
5
Tenga en cuenta que alterar la matriz de esa manera hace que los argumentos estén en orden inverso desde la línea de comando.
Andrew Backer
93

Si desea tener sus argumentos en estilo C (matriz de argumentos + número de argumentos) puede usar $@y $#.

$#te da el número de argumentos.
$@te da todos los argumentos. Puede convertir esto en una matriz mediante args=("$@").

Así por ejemplo:

args=("$@")
echo $# arguments passed
echo ${args[0]} ${args[1]} ${args[2]}

Tenga en cuenta que aquí ${args[0]}está el primer argumento y no el nombre de su script.

Stigi
fuente
5
Esto no responde a la pregunta: se trata de pasar los argumentos de la línea de comandos a una función de shell.
Cascabel
6
@Jefromi, en realidad, responde perfectamente a la pregunta. Puede utilizar la argsmatriz desde dentro de una función, si la inicializa de antemano como se describe.
vadipp
1
Encuentro esto mucho más limpio que iterar sobre los argumentos.
Félix Gagnon-Grenier
1
Esto es sencillo y sencillo. Gran respuesta. Publicó esto hace más de 7 años, así que hola desde el futuro: julio de 2017
SDsolar
Aún mejor sería citar como echo "${args[0]} ${args[1]} ${args[2]}", o los argumentos están sujetos a la expansión del nombre de archivo.
Benjamin W.
17
#!/usr/bin/env bash

echo name of script is $0
echo first argument is $1
echo second argument is $2
echo seventeenth argument is $17
echo number of arguments is $#

Editar: consulte mi comentario sobre la pregunta

Ravi Vyas
fuente
16

El comentario de Ravi es esencialmente la respuesta. Las funciones toman sus propios argumentos. Si desea que sean los mismos que los argumentos de la línea de comandos, debe pasarlos. De lo contrario, claramente está llamando a una función sin argumentos.

Dicho esto, si lo desea, puede almacenar los argumentos de la línea de comandos en una matriz global para usarlos en otras funciones:

my_function() {
    echo "stored arguments:"
    for arg in "${commandline_args[@]}"; do
        echo "    $arg"
    done
}

commandline_args=("$@")

my_function

Usted tiene que acceder a los argumentos de línea de comandos a través de la commandline_argsvariable no $@, $1, $2, etc, pero están disponibles. No conozco ninguna forma de asignar directamente a la matriz de argumentos, pero si alguien conoce una, ¡ilumíneme!

Además, observe la forma en que he usado y citado $@: así es como se asegura de que los caracteres especiales (espacios en blanco) no se estropeen.

Cascabel
fuente
6
# Save the script arguments
SCRIPT_NAME=$0
ARG_1=$1
ARGS_ALL=$*

function stuff {
  # use script args via the variables you saved
  # or the function args via $
  echo $0 $*
} 


# Call the function with arguments
stuff 1 2 3 4
Peter Coulton
fuente
2

Uno puede hacerlo así también

#!/bin/bash
# script_name function_test.sh
function argument(){
for i in $@;do
    echo $i
done;
}
argument $@

Ahora llama a tu guión como

./function_test.sh argument1 argument2
Vikash Singh
fuente
function print() {es una amalgama entre dos formas de declaración de función diferentes function print {, que es la sintaxis de ksh heredada que bash admite para compatibilidad con versiones anteriores de ksh pre-POSIX (es decir, pre-1991) y print() {, que está estandarizado por POSIX. Considere usar uno u otro para una mayor compatibilidad con otros proyectiles; ver también wiki.bash-hackers.org/scripting/obsolete
Charles Duffy
1

Puede utilizar la palabra clave shift (¿operador?) Para recorrerlos. Ejemplo:

#!/bin/bash
function print()
{
    while [ $# -gt 0 ]
    do
        echo $1;
        shift 1;
    done
}
print $*;
Marin Alcaraz
fuente
2
function print() {es una amalgama entre dos formas de declaración de función diferentes function print {, que es la sintaxis de ksh heredada que bash admite para compatibilidad con versiones anteriores de ksh pre-POSIX (es decir, pre-1991), y print() {que está estandarizado por POSIX. Considere usar uno u otro para una mayor compatibilidad con otros proyectiles; ver también wiki.bash-hackers.org/scripting/obsolete
Charles Duffy
1

Mi solución:

Cree un script de función que se llame antes que todas las demás funciones sin pasarle ningún argumento, como este:

! / bin / bash

función init () {ORIGOPT = "- $ @ -"}

Después de eso, puede llamar a init y usar la var ORIGOPT según sea necesario, como un plus, siempre asigno una nueva var y copio el contenido de ORIGOPT en mis nuevas funciones, de esa manera puede asegurarse de que nadie lo tocará o cambialo.

Agregué espacios y guiones para que sea más fácil analizarlo con 'sed -E', además, bash no lo pasará como referencia y hará que ORIGOPT crezca a medida que las funciones se llaman con más argumentos.

cabonamigo
fuente