como mudar um parâmetro e lançá-lo inteiramente de args ls?

como mudar um parâmetro e lançá-lo inteiramente de args ls?

Eu tenho um script que recebe N parâmetros. Primeiro ele os analisa (extrai um valor específico X) e depois chama outro programa com esse valor:

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

Quero adicionar um parâmetro opcional no início da lista de argumentos (parâmetro para definir a versão do python que estou executando). Então adicionei isso à função de análise:

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

No entanto, após o término da análise, fico preso porque isso shiftnão afeta a função de execução. Como posso fazer isso sem verificar novamente o valor do primeiro valor (o que anularia todo o propósito de ter uma função de análise)

Responder1

O escopo de cada função shell (bem como o escopo do código de nível superior no script) tem seu próprioparâmetros posicionais, e só pode acessar diretamente o seu próprio. A solução mais limpa é colocar os valores dos parâmetros posicionais de seu interesse emumvariedade. Você pode então ler e também modificar esse array em vários escopos de função.

Por exemplo, você poderia fazer com que este código aparecesse próximo ao início do seu script:

declare -a args=("$@")
  • Nomeie o array como quiser - ele não precisa ser chamado args.
  • Você pode até omitir declare -a, se quiser.
  • Realmente não precisa aparecer perto do começo. Só tem quecorrerantes de qualquer código que acessa argsser executado. Pode até aparecer abaixo das definições de funções shell que usam args. Para maior clareza, sugiro colocá-lo em algum lugar próximo ao início.

Então você pode operar no argsarray a partir de múltiplas funções. Você não precisa passá-lo para as funções; eles já poderão acessá-lo. Quando o código em uma função shell modifica o conteúdo argse depois retorna, o código do chamador poderá observar as alterações.

Parâmetros posicionais em shells estilo Bourne, incluindo Bash, usam indexação baseada em 1. (Isso ocorre porque $0, que se expande para o nome do programa, não é tecnicamente um parâmetro posicional e não muda nos escopos da função.) Mas os arrays no Bash usam indexação baseada em 0. Então, after args=("$@"), $1matches ${args[0]}, $2matches ${args[1]}, $3matches ${args[2]}, e assim por diante. $@ainda corresponde ${args[@]}como seria de esperar.

Eu os escrevi dessa forma, sem aspas, para facilitar a leitura. É claro que você quase sempre desejará colocar aspas duplas nas expansões que envolvem seu argsarray, assim como quase sempre deseja colocar aspas nas expansões que envolvem parâmetros posicionais.

Se você decidir seguir essa abordagem, em vez de:

shift

Você escreveria:

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

Se você é novo em arrays no Bash, você vai querer dar uma olhada ema parte relevante do manual de referência do Bash. Você também pode querer experimentar interativamente. Por exemplo:

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]

O código correspondente a

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

seria:

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

Usar um array é sintaticamente mais complicado, mas também mais flexível.

Por outro lado, como você parece ter a maior parte do código do seu script organizado em uma runfunção e seus destinatários, você pode considerar a alternativa de analisar quaisquer argumentos especiais da linha de comandoanteschamando run, fora de qualquer função shell e depois chamando run "$@"como você já está fazendo.

Existem linguagens de programação cujas culturas associadas têm uma forte ética de colocar quase tudo em funções pequenas e independentes. Bash não é uma linguagem assim, e as formas limitadas de retornar dados complexos de uma função shell são um dos motivos. Você não deve ter medo de escrever funções de shell e deve até estar disposto a escrever um grande número de pequenas funções de shell. Mas não acho que você deva se preocupar se descobrir que a melhor forma para o seu script é outra.

Para leitura adicional e algumas alternativas, incluindo uma abordagem estranha onde você obtém a saída da substituição do processo, consulteA resposta de GillesparaParâmetros posicionais do chamador de função.

informação relacionada