unshift args depois de chamar shift 1

6

Eu tenho este cenário

first_arg="$1";

if foo; then
    shift 1;
    node foo.js "$@"

elif bar; then

   shift 1;
    node bar.js "$@"

elif baz; then

   shift 1;
   node baz.js "$@"

else

   node default.js "$@"

fi

Eu gostaria de transformar o texto acima em:

first_arg="$1";
shift 1;

if foo; then

    node foo.js "$@"

elif bar; then

    node bar.js "$@"

elif baz; then

   node baz.js "$@"

else

   unshift 1;
   node default.js "$@"

fi

mas não tenho certeza se existe um operador como unshift, que acabei de inventar. Uma solução alternativa pode ser esta:

node default.js "$first_arg" "$@"

mas quando tentei isso, tive um comportamento estranho.

    
por Alexander Mills 13.07.2018 / 20:00

3 respostas

6

Você pode salvar seus argumentos em uma matriz:

args=( "$@"  )  # use double quotes
shift 1

if foo; then
  node foo.js "$@"
elif bar; then
  node bar.js "$@"
elif baz; then
  node baz.js "$@"
else
  node default.js "${args[@]}"
fi
    
por 13.07.2018 / 20:03
9

Você nunca precisa usar shift 1 em primeiro lugar. Basta usar os argumentos posicionais e dividir seus índices para passar os argumentos.

first_arg="$1"

Depois de fazer isso, o restante dos argumentos pode ser acessado como "${@:2}" . A notação é uma maneira de representar do argumento posicional 2 até o final da lista.

Usar a construção para o seu exemplo seria fazer

node foo.js "${@:2}"

e para a parte final else faça como

node default.js "$1" "${@:2}"

que é o mesmo que fazer "$@" , pois não há mudança de argumento posicional.

    
por 13.07.2018 / 20:11
7

A coisa que você tentou:

first_arg=$1
shift

# ...later...

else
    node default.js "$first_arg" "$@"
fi

Isso seria idêntico à sua primeira variante, desde que haja pelo menos um argumento de linha de comando.

Sem argumentos de linha de comando "$first_arg" ainda seria uma string vazia e, portanto, um argumento, enquanto "$@" não geraria nem mesmo uma string vazia.

Se o seu aplicativo Node aceitar um argumento vazio na linha de comando, isso pode fazer com que o aplicativo se comporte diferente em suas duas variantes de código.

Se chamar seu script sem argumentos de linha de comando é uma coisa válida a fazer, você poderia fazer

node default.js ${first_arg:+"$first_arg"} "$@"

em que ${first_arg:+"$first_arg"} seria expandido para nada se first_arg estivesse vazio ou não definido, mas para "$first_arg" if first_arg definido como uma string não vazia. Ou, se você quiser causar uma falha explícita por uma variável não definida ou vazia:

node default.js "${first_arg:?Error, no command line arguments}" "$@"

Alternativas inclui fazer uma cópia de $@ como bash array como Jesse_b mostra em sua resposta .

Colocar $first_arg de volta em $@ com

set -- "$first_arg" "$@"'

não funcionaria, pois isso incluiria um argumento vazio como $1 in $@ se o argumento da linha de comando estivesse faltando.

com

set -- ${first_arg:+"$first_arg"} "$@"'

você "não mudaria" nada se $first_arg estivesse vazio ou se a variável não existisse.

Note que shift é o mesmo que shift 1 e que instruções únicas não precisam ser terminadas por; a menos que seja seguido por outra instrução na mesma linha (newline é um terminador de comando, assim como;).

    
por 13.07.2018 / 20:21