Aqui está um pequeno truque que eu tive que usar para obter o resultado desejado da implementação do meu analisador de opções. Eu estava usando zparseopts
, um equivalente zsh de conchas bourne getopt(s)
.
Deixe-me ilustrar o problema que enfrentei, se alguém tiver uma maneira (mais) idiomática de fazer isso (também conhecido como esqueci algum recurso / opção), eu estaria interessado em descobrir.
O que eu queria era uma análise de opção repetida. Não tenho nenhum valor padrão, também não gosto de usar um opts
array, pois acho que também poderia demonstrar essa rota depois, pois ela destaca perfeitamente meu dilema.
Digamos que eu tenha uma função que aceita vários argumentos de arquivo. Claro que eu poderia usar uma lista de nomes de arquivo separados por dois pontos ou por espaço, mas eu queria / precisava deles como opções separadas.
#!/usr/bin/env zsh
function zomg/check()
{
zparseopts -D -E -- f+:=files -files+:=files
}
O que acabei de fazer foi declarar uma função chamada zomg/check
e nela coloquei nosso analisador de opções que tem a -D
chave (para remover quaisquer opções encontradas na lista de argumentos posicionais) e a -E
chave (para não parar quando opções desconhecidas – não em as especificações – são encontradas) definidas. Eu geralmente gosto de manter esses dois por perto, embora tecnicamente eles não sejam realmente necessários aqui ainda.
As partes seguintes --
são chamadas de especificações e devem estar no formato . No nosso caso, temos duas especificações que se referem ao mesmo array, a saber . A primeira é a opção e a segunda são as opções longas (denotadas por um único hífen de prefixo ). O sinal de mais indica que desejamos que essa opção seja usada repetidamente, se não exigirmos isso explicitamente, apenas a última fornecida ou será armazenada. Os únicos dois pontos indicam que esta opção é opcional.opt[=array]
files
-f
--files
-
+
-f
--file
:
Para tornar um pouco mais fácil, aqui está uma reescrita da mesma função sem o extra apenas esqueleto:
zparseopts -- f+:=storage -files+:=storage
Agora, nosso armazenamento é do tipo array, portanto, devemos ser capazes de referenciá-lo usando o índice para recuperar elementos.
Vamos dar uma olhada rápida em como o array de variáveis (lista) fica depois de passá-lo zomg/check -f foo -f bar -f baz
print $storage[@]
-f foo -f bar -f baz
Como você pode ver, este é o padrão repetido e verificar quantos elementos este array possui
print ${#storage}
Vai nos dizer 6
como resultado. Isso nos deixa com a tarefa de filtrar os valores. Como esse array não é do tipo associativo (dicionário, mapa hash, armazenamento de chave / valor), não podemos simplesmente fazer e obter nossa lista de 3 elementos retornada. Conforme eu vim, encontrei duas maneiras razoavelmente fáceis de expressar os valores.${(v)storage}
foo bar baz
A primeira é a mais fácil: eliminamos todas as ocorrências de em nossa matriz:-f
storage=("${(@)storage:#-f}")
print $storage[@]
Irá retornar foo bar baz
e testar o comprimento do array usando retornará como resposta. No entanto, ele não conseguiria remover nenhum do array.${#storage}
3
--files
O segundo método é um pouco mais elaborado, embora também mais divertido, e não falha em remover qualquer opção longa de opções de sinônimo / alias. Raciocinamos como se tivéssemos um dicionário de pares de valores-chave (use um auxiliar) para obter uma lista de inteiros pares e ímpares. Os números ímpares começando em 1 serão as chaves e, subsequentemente, os números pares formam os nossos valores:
typeset -A helper
helper=($(seq 1 ${#storage}))
O que acabamos de fazer é criar um array associativo que é preenchido pela sequência de números neste caso 6. O array gerado por zparseopts nos garante um número par de elementos, contanto que testemos o valor zero no segundo elemento. Eu sempre uso para isso.1..to..number of elements in array
test -z ${storage[2]}
Com esses pares de chave / valor de , e agora podemos obter facilmente os elementos de nossa matriz unidimensional regular por meio de nossos valores como número de índice:1 and 2
3 and 4
5 and 6
for item in ${(@v)helper}
do
print ${storage[$item]}
done
Isso fará um loop de números 2
, 4
e 6
que se correlacionam com as posições na lista (-f foo -f bar -f baz)
e, como tal, extraem os dados para nós.