¿Qué significa $# en bash?

¿Qué significa $# en bash?

Tengo un script en un archivo llamado instancia:

echo "hello world"
echo ${1}

Y cuando ejecuto este script usando:

./instance solfish

Obtengo este resultado:

hello world
solfish

Pero cuando corro:

echo $# 

Dice "0". ¿Por qué? No entiendo lo que $#significa.

Por favor explícalo.

Respuesta1

$#es una variable especial en bash, que se expande al número de argumentos (parámetros posicionales), es decir, $1, $2 ...pasados ​​al script en cuestión o al shell en caso de que el argumento se pase directamente al shell, por ejemplo, en bash -c '...' .....

Esto es similar a argcC.


Quizás esto lo aclare:

$ bash -c 'echo $#'
0

$ bash -c 'echo $#' _ x
1

$ bash -c 'echo $#' _ x y
2

$ bash -c 'echo $#' _ x y z
3

Tenga en cuenta que bash -ctoma un argumento después del comando que le sigue comenzando desde 0 ( $0; técnicamente, es solo bashuna forma de permitirle configurar $0, no un argumento en realidad), por lo que _se usa aquí solo como un marcador de posición; Los argumentos reales son x( $1), y( $2) y z( $3).


De manera similar, en su script (asumiendo script.sh) si tiene:

#!/usr/bin/env bash
echo "$#"

Entonces cuando lo hagas:

./script.sh foo bar

el script generará 2; asimismo,

./script.sh foo

generará 1.

Respuesta2

echo $#genera el número de parámetros posicionales de su script.

No tiene ninguno, por lo que genera 0.

echo $#es útil dentro del script, no como un comando separado.

Si ejecuta un script con algunos parámetros como

./instance par1 par2

el echo $#colocado en el script generará 2.

Respuesta3

$#se utiliza normalmente en scripts bash para garantizar que se pase un parámetro. Generalmente, verifica un parámetro al comienzo de su secuencia de comandos.

Por ejemplo, aquí hay un fragmento de un guión en el que estuve trabajando hoy:

if [[ $# -ne 1 ]]; then
    echo 'One argument required for the file name, e.g. "Backup-2017-07-25"'
    echo '.tar will automatically be added as a file extension'
    exit 1
fi

Para resumir $#informa el número de parámetros pasados ​​a un script. En su caso, no pasó ningún parámetro y el resultado informado es 0.


Otros #usos en Bash

Se #usa a menudo en bash para contar el número de apariciones o la longitud de una variable.

Para encontrar la longitud de una cuerda:

myvar="some string"; echo ${#myvar}

devoluciones:11

Para encontrar el número de elementos de la matriz:

myArr=(A B C); echo ${#myArr[@]}

devoluciones:3

Para encontrar la longitud del primer elemento de la matriz:

myArr=(A B C); echo ${#myArr[0]}

devuelve: 1(La longitud de A, 0 es el primer elemento ya que las matrices utilizan índices/subíndices de base cero).

Respuesta4

$#es el número de argumentos, pero recuerda 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, elLos parámetros posicionales se reemplazan temporalmente con los argumentos de la función.. Esto permite que las funciones acepten y utilicen sus propios parámetros posicionales.

Este script siempre imprime 3, independientemente de cuántos argumentos se pasaron al script en sí, porque "$#"en la función fse expande al número de argumentos pasados ​​a la función:

#!/bin/sh

f() {
    echo "$#"
}

f a b c

Esto es importante porque significa que código como este no funciona como cabría esperar si no está familiarizado con cómo funcionan los parámetros posicionales en las funciones del 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 misma, que en ese script siempre es 0.

Si desea dicha funcionalidad en una función de shell, tendría que escribir algo como esto:

#!/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.afuerala función y se pasa a la función como uno deesparámetros posicionales. Dentro de la función, $1se expande al primer parámetro posicional que se pasó a la función de shell, en lugar del 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¿noCambie el nombre de la función, razón por la cual aún pude usarla para generar un mensaje de error de calidad.

$ ./check-args-demo a b c
./check-args-demo: error: need 2 arguments, got 3

De manera similar, si defines una función dentro de otra, estás 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 nestedy (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ás 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 hayas cambiado.

Una forma común de cambiarlos es con el shiftincorporado, que desplaza cada parámetro posicional hacia la izquierda en uno, eliminando 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 setincorporado:

#!/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

información relacionada