Como acessar os argumentos da linha de comando do chamador dentro de uma função?

95

Estou tentando escrever uma função em bash que acessará os argumentos de linha de comando do script, mas eles foram substituídos pelos argumentos posicionais da função. Existe alguma maneira de a função acessar os argumentos da linha de comando se eles não forem passados ​​explicitamente?

# 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
fonte
3
Estou meio confuso, você quer as args sem passá-las?
Ravi Vyas
4
Sim, o objetivo é obter também os argumentos da linha de comando de dentro de uma função sem transmiti-los como argumentos funcionais. Isso tem a ver com uma situação de tratamento de erros em que desejo fazer o tratamento de erros com base em argumentos de linha de comando, independentemente dos argumentos passados ​​para a função.
DonGar
Para sua informação, $*é extremamente problemático - ele mudará ./yourScript "first argument" "second argument"para ./yourscript "first" "argument" "second" "argument", ou mudará ./yourscript '*.txt'para algo como, ./yourscript one.txt two.txtapesar das aspas.
Charles Duffy

Respostas:

46

Minha leitura do manual de referência do bash diz que essas coisas são capturadas em BASH_ARGV, embora fale muito sobre "a pilha".

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

Salvar em 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
fonte
5
Observe que a iteração do array dessa forma faz com que os argumentos fiquem na ordem inversa da linha de comando.
Andrew Backer
93

Se você quiser ter seus argumentos no estilo C (matriz de argumentos + número de argumentos), você pode usar $@e $#.

$#fornece o número de argumentos.
$@dá a você todos os argumentos. Você pode transformar isso em uma matriz por args=("$@").

Então, por exemplo:

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

Observe que aqui ${args[0]}está realmente o primeiro argumento e não o nome do seu script.

Stigi
fonte
5
Isso não resolve a questão - está perguntando sobre como passar os argumentos da linha de comando para uma função shell.
Cascabel
6
@Jefromi, na verdade, responde à pergunta perfeitamente. Você pode usar o argsarray de dentro de uma função, se você inicializá-lo de antemão conforme descrito.
vadipp
1
Acho isso muito mais limpo do que iterar sobre os argumentos.
Félix Gagnon-Grenier
1
Isso é simples e fácil. Ótima resposta. Você postou isto há mais de 7 anos, então, olá do futuro: julho de 2017
SDsolar
Melhor ainda seria citar like echo "${args[0]} ${args[1]} ${args[2]}", ou os argumentos estão sujeitos à expansão do nome do arquivo.
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 $#

Edit: por favor, veja meu comentário sobre a questão

Ravi Vyas
fonte
16

O comentário de Ravi é essencialmente a resposta. As funções usam seus próprios argumentos. Se quiser que eles sejam iguais aos argumentos da linha de comando, você deve passá-los. Caso contrário, você está claramente chamando uma função sem argumentos.

Dito isso, você poderia, se quiser, armazenar os argumentos da linha de comando em uma matriz global para usar em outras funções:

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

commandline_args=("$@")

my_function

Você tem que acessar os argumentos de linha de comando através da commandline_argsvariável, não $@, $1,$2 , etc., mas eles estão disponíveis. Não tenho conhecimento de nenhuma maneira de atribuir diretamente ao array de argumentos, mas se alguém conhecer um, por favor, esclareça-me!

Além disso, observe a maneira como usei e citei $@- é assim que você garante que os caracteres especiais (espaços em branco) não sejam bagunçados.

Cascabel
fonte
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
fonte
2

Pode-se fazer assim também

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

Agora chame seu script de

./function_test.sh argument1 argument2
Vikash Singh
fonte
function print() {é um amálgama entre duas formas de declaração de função diferentes - function print {, que é a sintaxe ksh legada que o bash suporta para compatibilidade com versões anteriores com ksh pré-POSIX (ou seja, pré-1991) e print() {, que é padronizado por POSIX. Considere usar um ou outro para compatibilidade mais ampla com outros shells; veja também wiki.bash-hackers.org/scripting/obsolete
Charles Duffy
1

Você pode usar a palavra-chave shift (operador?) Para iterar por eles. Exemplo:

#!/bin/bash
function print()
{
    while [ $# -gt 0 ]
    do
        echo $1;
        shift 1;
    done
}
print $*;
Marin Alcaraz
fonte
2
function print() {é um amálgama entre duas formas de declaração de função diferentes - function print {, que é a sintaxe legada do ksh que o bash suporta para compatibilidade com versões anteriores do ksh pré-POSIX (ou seja, pré-1991) e print() {, que é padronizado pelo POSIX. Considere usar um ou outro para compatibilidade mais ampla com outros shells; veja também wiki.bash-hackers.org/scripting/obsolete
Charles Duffy
1

Minha solução:

Crie um script de função que seja chamado antes de todas as outras funções sem passar nenhum argumento para ele, como este:

! / bin / bash

função init () {ORIGOPT = "- $ @ -"}

Depois disso, você pode chamar o init e usar o ORIGOPT var conforme necessário, como um plus, eu sempre atribuo uma nova var e copio o conteúdo do ORIGOPT em minhas novas funções, dessa forma você pode ter certeza de que ninguém vai tocar nele ou mude.

Eu adicionei espaços e travessões para tornar mais fácil analisá-lo com 'sed -E' também o bash não o passará como referência e fará ORIGOPT crescer conforme as funções são chamadas com mais argumentos.

cabonamigo
fonte