Como mudar argumentos enquanto os argumentos começam com -

2

Digamos que eu tenha uma função bash, que deve remover todos os argumentos que começam com "-" até chegar a um argumento que não comece com "-".

gmx(){

  local options=( );

  while [ "${1:0:1}" == "-"  ]; do
    options+=("${1}")
    shift 1;
  done

  echo "first legit arg: $1"
  "$@" # omg will be executed here, like 'omg --rolo'
}

gmx -a -f -c omg --rolo

isso parece funcionar, mas eu estou querendo saber se essa é uma boa solução genérica para sempre fazer com que 'omg' seja o primeiro argumento "legítimo". Há algum caso extremo que possa falhar?

Em outras palavras, -a, -f, -c são todos argumentos para gmx. Considerando que omg e tudo o que se segue, será executado em um processo filho.

    
por Alexander Mills 24.06.2018 / 22:02

3 respostas

7

A maneira oficial e melhor é usar o getopts embutido para analisar as opções da linha de comando.

Veja a man page para mais informações.

Uma nota pode ser importante: bash não suporta opções longas.

Se você gosta de scripts para lidar com opções longas, você tem dois shells que os suportam: ksh93 e bosh . Ambos os shells suportam opções longas da maneira como são suportadas pela função getopt(3) no libc no Solaris. Veja a man page do bosh (a partir de agora na página 43:

link

getopts "f:(file)(input-file)o:(output-file)" OPT

suporta, por exemplo, uma opção -f com um argumento e essa opção tem uma opção longa alias --file e um segundo alias para esta opção --input-file

O ksh93 também suporta isto, apesar de não estar documentado na página do manual do ksh93.

    
por 24.06.2018 / 22:08
4
while getopts ':' opt; do
    :    # This is where ordinarily a case statement would be,
         # case $opt in ... esac
         # But we use : as a no-op
done

shift "$(( OPTIND - 1 ))"
printf 'arg: %s\n' "$@"

Isso usa getopts para analisar as opções da linha de comando. O while loop terminará assim que a primeira não opção for encontrada, e o shift deslocará as opções processadas de $@ deixando apenas os operandos que não são opções em $@ .

O script

#!/bin/sh

gmx () {
    while getopts ':' opt; do
        :
    done

    shift "$(( OPTIND - 1 ))"
    printf 'arg: %s\n' "$@"
}

gmx -a --foo -c omg lol

produziria

arg: omg
arg: lol

Como você não está interessado em saber quais são as opções reais, obviamente você pode fazer um loop simples como

for opt do
    case $opt in
        -*) shift ;;
        *)  break
     esac
done

printf 'arg: %s\n' "$@"

Isso faz um loop sobre todos os argumentos, mudando de cada um que começa com um traço e termina no primeiro que não começa com um traço.

    
por 24.06.2018 / 22:10
2

Uma solução muito mais simples, se você tiver controle sobre a maneira como o gmx é chamado, é simplesmente separar argumentos do wrapper do comando wrapped usando -- , como tal

gmx garg garg garg -- warg warg warg

onde

  • garg significa um argumento usado por gmx .
  • warg significa um argumento enviado para warg .

Se você quiser a conveniência de omitir -- , poderá torná-lo opcional e pesquisá-lo antes de tentar a verificação "inteligente".

    
por 25.06.2018 / 02:21