Estou tentando passar todos os parâmetros de um script para outro. No entanto, há um problema quando o outro script é originado; todos os parâmetros não estão passando corretamente.
primeiro.sh:
#!/usr/bin/bash
while getopts a option
do
case "${option}"
in
a) echo 'OptionA:somevalue';;
esac
done
# This way works
./second.sh "$@"
# Does not work when source command is used
#source ./second.sh "$@"
segundo.sh:
#!/usr/bin/bash
while getopts b:c option
do
case "${option}"
in
b) echo 'OptionB:'"${OPTARG}";;
c) echo 'OptionC:somevalue';;
esac
done
Saída:
$ ./test.sh -a -b foo -c
OptionA:somevalue
./first.sh: illegal option -- b
./second.sh: illegal option -- a
OptionB:foo
OptionC:somevalue
Resultado esperado:
$ ./test.sh -a -b foo -c
OptionA:somevalue
OptionB:foo
OptionC:somevalue
O que conseguir?
Passando os parâmetros corretamente para second.sh
o comando source, livrando-se illegal option
e compatibilidade com outros shells.
Editar: atualizei a pergunta novamente com exemplos mais claros.
Considere como um
while getopts
loop funciona mesmo no caso normal.getopts
é chamado para cada iteração do loop e, embora não modifique os próprios argumentos da linha de comando (parâmetros posicionais), de alguma forma ele precisa saber onde procurar na lista de argumentos a seguir. Tem que fazer isso mantendo o estado "oculto", algo não passado explicitamente na chamada.Isso está descrito no manual de referência do Bash :
Quando você cria um script, ele é executado no mesmo ambiente shell que o script principal, e isso inclui arquivos
OPTIND
.Conforme sugerido no manual, basta definir
OPTIND=1
antes de iniciar um novogetopts
loop. (Não tente desativá-lo, pois isso pode causar problemas em alguns shells.)Como exemplo, este:
estampas
já que o segundo loop continua a partir da posição em que o primeiro parou, perdendo o
-b first
.Remova o comentário da
OPTIND=1
tarefa no meio e você obterá o resultado esperado:Quanto ao armazenamento dos argumentos separadamente de
$@
, doingargs+="-a ${OPTARG} "
cria uma única string, enquanto o conjunto de argumentos da linha de comando é na verdade uma lista/matriz de strings distintas. A diferença é mais evidente quando qualquer um dos argumentos contém espaços em branco. Os dois conjuntos de argumentos (-a
,foo bar
) e (-a foo
,bar
) se unem-a foo bar
e não há como saber a diferença da última string.Em vez disso, use um array para armazenar os argumentos como strings distintas.
(Veja Como podemos executar um comando armazenado em uma variável? para mais exemplos, etc.)
Observe que o comando padrão
.
(ponto) para obter um script não aceita argumentos, mas em vez disso, o script de origem vê o mesmo$@
que o script principal. (E as alterações feitas$@
no script de origem são visíveis no script principal.)Embora
.
o / do Bashsource
suporte a passagem de um novo conjunto de argumentos, se você chamarsource filename
sem um conjunto de argumentos, o script de origem não obterá uma lista vazia, mas os argumentos do script principal.Então, se você fizer isso:
você pode querer ter o cuidado de verificar se
args
não está vazio. Ou apenas redefina os argumentos do script principal antes de obter o outro. Claro, isso irá destruir o conjunto original de argumentos, mas se você precisar deles, você pode salvá-los primeiro em outro array: