Bash: Por que é usado eval e shift em um script que analisa argumentos de linha de comando?

3

Como eu estava procurando essa resposta link para descobrir como usar parâmetros como --something ou -s algumas questões levantadas em relação ao roteiro da resposta:

#!/bin/bash
TEMP='getopt -o ab:c:: --long a-long,b-long:,c-long:: \
     -n 'example.bash' -- "$@"'

if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi

# Note the quotes around '$TEMP': they are essential!
eval set -- "$TEMP"

while true ; do
    case "$1" in
        -a|--a-long) echo "Option a" ; shift ;;
        -b|--b-long) echo "Option b, argument \'$2'" ; shift 2 ;;
        -c|--c-long) 
            # c has an optional argument. As we are in quoted mode,
            # an empty parameter will be generated if its optional
            # argument is not found.
            case "$2" in
                "") echo "Option c, no argument"; shift 2 ;;
                *)  echo "Option c, argument \'$2'" ; shift 2 ;;
            esac ;;
        --) shift ; break ;;
        *) echo "Internal error!" ; exit 1 ;;
    esac
done
echo "Remaining arguments:"
for arg do echo '--> '"\'$arg'" ; done

Primeiro, o que o programa shift na seguinte linha:

        -a|--a-long) echo "Option a" ; shift ;;

Depois, qual é o propósito de usar o comando eval na seguinte linha:

eval set -- "$TEMP"

Eu tentei comentar a linha no script mencionado acima e recebi a seguinte resposta:

$ ./getOptExample2.sh  -a 10 -b 20 --a-long 40 -charem --c-long=echi
Param: -a
Option a
Param: 10
Internal error!

Mas se eu descomente-o, funciona como um encanto:

Option a
Option b, argument '20'
Option a
Option c, argument 'harem'
Option c, argument 'echi'
Remaining arguments:
--> '10'
--> '40'
    
por Dimitrios Desyllas 04.08.2017 / 09:12

2 respostas

4

Uma das muitas coisas que getopt faz ao analisar as opções é reorganizar os argumentos, de modo que os argumentos não opcionais sejam os últimos e as opções curtas combinadas sejam divididas. De man getopt :

Output is generated for each element described in the previous section.
Output is done in the same order as the elements are specified  in  the
input,  except  for  non-option  parameters.   Output  can  be  done in
compatible (unquoted) mode, or in such way that  whitespace  and  other
special  characters  within  arguments  and  non-option  parameters are
preserved (see QUOTING).  When the output is  processed  in  the  shell
script,  it  will  seem to be composed of distinct elements that can be
processed one by  one  (by  using  the  shift  command  in  most  shell
languages).

[...]

Normally, no  non-option  parameters  output  is  generated  until  all
options  and  their  arguments  have  been  generated.   Then  '--'  is
generated as a single parameter, and after it the non-option parameters
in  the  order  they were found, each as a separate parameter.

Este efeito é refletido no seu código, onde o loop de manipulação de opções assume que todos os argumentos da opção (incluindo argumentos para opções) vêm em primeiro lugar, e vêm separadamente e são finalmente seguidos por não opção argumentos.

Portanto, TEMP contém as opções de divisão, cotação e rearranjadas, e usar eval set faz delas argumentos de script.

Quanto a shift , ele faz o que sempre faz: remover o primeiro argumento e alterar todos os argumentos (para que o que é $2 seja $1 ). Isso elimina os argumentos que foram processados, de modo que, após esse loop, apenas argumentos não opcionais são deixados e você pode usar convenientemente $@ sem se preocupar com opções.

    
por 04.08.2017 / 09:30
1

O script funciona corretamente quando você recebe um erro para -a 10 . A opção -a não precisa de parâmetro neste script. Você deve usar apenas -a .

O deslocamento descrito na man page é o seguinte:

shift [n]
              The positional parameters from n+1 ... are renamed to $1 ....  Parameters represented by the numbers $# down to $#-n+1 are unset.  n must be a non-negative number less than or equal to $#.  If  n  is
              0,  no  parameters are changed.  If n is not given, it is assumed to be 1.  If n is greater than $#, the positional parameters are not changed.  The return status is greater than zero if n is greater
              than $# or less than zero; otherwise 0.

Então, basicamente, cai -a e desloca os argumentos restantes para que o segundo parâmetro seja $ 1 no próximo ciclo.

-- também é descrito na página man:

 --        A -- signals the end of options and disables further option processing.  Any arguments after the -- are treated as filenames and arguments.  An argument of - is equivalent to --.
    
por 04.08.2017 / 09:35