$#
es el número de argumentos, pero recuerde que será diferente en una función.
$#
es el número de parámetros posicionales pasados al script, shell o función de shell . Esto se debe a que, mientras se ejecuta una función de shell, los parámetros posicionales se reemplazan temporalmente con los argumentos de la función . Esto permite que las funciones acepten y usen sus propios parámetros posicionales.
Este script siempre se imprime 3
, independientemente de cuántos argumentos se pasaron al script en sí, porque "$#"
en la función se f
expande a la cantidad de argumentos pasados a la función:
#!/bin/sh
f() {
echo "$#"
}
f a b c
Esto es importante porque significa que un código como este no funciona como cabría esperar, si no está familiarizado con el funcionamiento de los parámetros posicionales en las funciones de shell:
#!/bin/sh
check_args() { # doesn't work!
if [ "$#" -ne 2 ]; then
printf '%s: error: need 2 arguments, got %d\n' "$0" "$#" >&2
exit 1
fi
}
# Maybe check some other things...
check_args
# Do other stuff...
En check_args
, se $#
expande al número de argumentos pasados a la función en sí, que en ese script siempre es 0.
Si desea dicha funcionalidad en una función de shell, tendría que escribir algo como esto en su lugar:
#!/bin/sh
check_args() { # works -- the caller must pass the number of arguments received
if [ "$1" -ne 2 ]; then
printf '%s: error: need 2 arguments, got %d\n' "$0" "$1" >&2
exit 1
fi
}
# Maybe check some other things...
check_args "$#"
Esto funciona porque $#
se expande fuera de la función y se pasa a la función como uno de sus parámetros posicionales. Dentro de la función, se $1
expande al primer parámetro posicional que se pasó a la función de shell, en lugar de al script del que forma parte.
Por lo tanto, al igual que $#
, los parámetros especiales $1
, $2
, etc., así como $@
y $*
, también pertenecen a los argumentos pasados a una función, cuando se expanden en la función. Sin embargo, $0
no no cambiar el nombre de la función, que es por lo que todavía era capaz de utilizarlo para producir un mensaje de error de la calidad.
$ ./check-args-demo a b c
./check-args-demo: error: need 2 arguments, got 3
Del mismo modo, si define una función dentro de otra, está trabajando con los parámetros posicionales pasados a la función más interna en la que se realiza la expansión:
#!/bin/sh
outer() {
inner() {
printf 'inner() got %d arguments\n' "$#"
}
printf 'outer() got %d arguments\n' "$#"
inner x y z
}
printf 'script got %d arguments\n' "$#"
outer p q
Llamé a este script nested
y (después de ejecutarlo chmod +x nested
) lo ejecuté:
$ ./nested a
script got 1 arguments
outer() got 2 arguments
inner() got 3 arguments
Sí, lo sé. "1 argumentos" es un error de pluralización.
Los parámetros posicionales también se pueden cambiar.
Si está escribiendo un script, los parámetros posicionales fuera de una función serán los argumentos de la línea de comandos pasados al script a menos que los haya cambiado .
Una forma común de cambiarlos es con el shift
incorporado, que desplaza cada parámetro posicional hacia la izquierda en uno, bajando el primero y disminuyendo $#
en 1:
#!/bin/sh
while [ "$#" -ne 0 ]; do
printf '%d argument(s) remaining.\nGot "%s".\n\n' "$#" "$1"
shift
done
$ ./do-shift foo bar baz # I named the script do-shift.
3 argument(s) remaining.
Got "foo".
2 argument(s) remaining.
Got "bar".
1 argument(s) remaining.
Got "baz".
También se pueden cambiar con el set
incorporado:
#!/bin/sh
printf '%d args: %s\n' "$#" "$*"
set foo bar baz
printf '%d args: %s\n' "$#" "$*"
$ ./set-args a b c d e # I named the script set-args.
5 args: a b c d e
3 args: foo bar baz
$#
? ¿Qué quieres lograr? ¿De dónde sacaste este comando? No es relevante en absoluto.