Explique o comando shell: shift $ (($ optind - 1))

30

Eu não sou um cara do Linux, mas preso em algum script que eu tenho que ler para o meu projeto. Então, alguém pode me ajudar com o que esse comando está fazendo?

shift $(($optind - 1))
Calça Gaurav
fonte
3
Conforme observado abaixo, OPTIND deve estar em maiúsculas e o '$' entre parênteses é opcional.
DarkHeart 6/07

Respostas:

49

shift $((OPTIND-1))(nota OPTINDé maiúscula) normalmente é encontrado imediatamente após um getopts whileloop. $OPTINDé o número de opções encontradas por getopts.

Como pauljohn32 menciona nos comentários, estritamente falando, OPTINDfornece a posição do próximo argumento da linha de comando.

No Manual de Referência do GNU Bash :

getopts optstring nome [args]

getoptsé usado por scripts de shell para analisar parâmetros posicionais. optstringcontém os caracteres de opção a serem reconhecidos; se um caractere for seguido por dois pontos, espera-se que a opção tenha um argumento, que deve ser separado por espaço em branco. Os dois pontos (':') e o ponto de interrogação ('?') Não podem ser usados ​​como caracteres de opção. Sempre que é chamado, getoptscoloca a próxima opção no nome da variável do shell, inicializando namese não existir, e o índice do próximo argumento a ser processado na variável OPTIND. OPTINDé inicializado como 1 sempre que o shell ou um script de shell é chamado. Quando uma opção requer um argumento, getopts coloca esse argumento na variável OPTARG. O shell não é redefinidoOPTIND automaticamente; ele deve ser redefinido manualmente entre várias chamadas para getoptsdentro da mesma invocação de shell se um novo conjunto de parâmetros for usado.

Quando o final das opções é encontrado, getoptssai com um valor de retorno maior que zero. OPTINDé definido como o índice do primeiro argumento não opcional e o nome é definido como '?'.

getoptsnormalmente analisa os parâmetros posicionais, mas se houver mais argumentos args, getoptsanalisa-os.

shift n
remove n strings da lista de parâmetros posicionais. Assim, shift $((OPTIND-1))remove todas as opções analisadas getoptsda lista de parâmetros e, depois desse ponto, $1se refere ao primeiro argumento de não opção transmitido para o script.

Atualizar

Como mikeserv menciona no comentário, shift $((OPTIND-1))pode não ser seguro. Para evitar a divisão indesejada de palavras, etc, todas as expansões de parâmetro devem ser citadas duas vezes. Portanto, o formulário seguro para o comando é

shift "$((OPTIND-1))"

PM 2Ring
fonte
Parece que isso só funcionará corretamente se todas as opções ocorrerem antes dos argumentos posicionais restantes. Corrigir?
Steve Jorgensen
@SteveJorgensen: Sim, está correto. OTOH, colocar opções após argumentos que não são de opção vai contra a convenção sh / bash. Geralmente, os primeiros argumentos que não começam com um traço significam o fim das opções e quaisquer argumentos subsequentes que começam com um traço não são considerados opções. Nem todos os programas aderem a essa convenção, mas isso torna a vida muito mais simples. :)
PM 2Ring
@SteveJorgensen: (cont) Este tópico é discutido brevemente em Por que alguns utilitários analisam operandos antes das opções? . Como o comentário de Gilles à resposta de Celada menciona, alguns programas (como find) podem parecer que permitem opções após não-opções, mas não o fazem: eles têm operandos que começam com um traço.
PM 2Ring
Obrigado por essa informação (e pela edição) @mosvy Isso é bastante incomum IFS, mas é melhor prevenir do que remediar. ;)
PM 2Ring
@roaima if IFS=0123456789,shift $((OPTIND-1)) (sem aspas) se transformará no shift ""que será silenciosamente ignorado (in ksh) ou gerará um erro (in bashe dash).
mosvy 04/07
8

$((...))apenas calcula coisas. No seu caso, leva o valor de $optinte substracts 1.

shiftremove parâmetros posicionais. No seu caso, ele remove optint-1parâmetros.

Para mais informações dê uma olhada help getopts, help shift, olhada man bashpara "Expansão Aritmética", e especialmente o Google para getopts.

michas
fonte