awk atribui a várias variáveis ​​de uma só vez

9

Estou tentando extrair dois valores numéricos de uma string e atribuí-los a variáveis ​​usando awk( gawké o que estou usando especificamente). Eu quero puxar os números de versão principais e secundários de uma string de versão do tmux para awkvariáveis, por exemplo:

  • entrada tmux 2.8:; maj == 2emin == 8
  • entrada tmux 1.9a:; maj == 1emin == 9
  • entrada tmux 2.10:; maj == 2emin == 10

Assumindo que minha entrada vem do tmux -Vstdin, atualmente tenho o seguinte:

tmux -V | awk '{
                  maj = +gensub(/([0-9]+)\..*/, "\\1", "g", $2);
                  min = +gensub(/.*\.([0-9]+).*/, "\\1", "g", $2);
                  # ...do something with maj and min...
               }'

Isso funciona, mas como muitos usuários de tmux saber, usando if-shellno .tmux.confarquivo (onde espero usar este material) pode facilmente levar a muito longas filas no arquivo de configuração, então eu estou querendo saber se há uma maneira de combinar essas duas variáveis atribuições em uma instrução para economizar espaço ... ou qualquer outra maneira de coletar essas duas variáveis ​​da entrada e economizar espaço.

Estou pensando em algo como:

awk '{ maj, min = +gensub(/([0-9]+)\.([0-9]+).*/, "\\1 \\2", "g", $2); }'

... como em Python, mas essa sintaxe específica não existe awk. Existe mais alguma coisa possível?

Observe que a legibilidade não é realmente uma preocupação, apenas o comprimento.

villapx
fonte

Respostas:

9

Observe que gensubé uma gawkextensão, não funcionará com nenhuma outra awkimplementação. Observe também que o +operador unário não força a conversão numérica em todas as awkimplementações, o uso + 0é mais portátil.

Aqui você pode fazer:

tmux -V | awk -F '[ .]' '{maj = $2+0; min = $3+0; print maj, min}'

Se você não se importa em usar awkextensões GNU , também pode:

tmux -V | awk -v FPAT='[0-9]+' '{maj = $1; min = $2; print maj, min}'
Stéphane Chazelas
fonte
Obrigado pelas explicações adicionais sobre compatibilidade!
21419 villapx
13

Como você está usando o GNU awk, você pode usar a forma de três argumentos match()para armazenar vários grupos de captura:

awk '
    match($0, /([0-9]+)\.([0-9]+)/, m) {maj=m[1]; min=m[2]; print maj, min}
' <<END
tmux 2.8
tmux 1.9a
tmux 2.10
END
2 8
1 9
2 10

https://www.gnu.org/software/gawk/manual/html_node/String-Functions.html

Glenn Jackman
fonte
5

Você pode dividir a versão em uma matriz:

awk '{ split($2, ver, /[.a-z]/) }'

então use em ver[1]vez de maj, em ver[2]vez de min.

A adição a-zao separador remove qualquer letra minúscula do número da versão. (As outras soluções são melhores aqui, pois extraem números explicitamente.)

Stephen Kitt
fonte
3

Outro usuário postou esta resposta e mais tarde foi excluída. Eu pensei que era útil:

Usando a split()função, divida a string da versão em uma matriz ver, acesse ver[1]e em ver[2]vez de maje min, respectivamente (ou simplesmente armazene os valores nessas variáveis):

tmux -V | awk '{ split($2, ver, /[.a-z]/); print ver[1], ver[2] }'

A vantagem aqui é que split()não é uma gawkextensão (embora seu quarto argumento opcional sepsseja).

villapx
fonte
+1, mas por que usar /[.a-z]/como o terceiro argumento (separação de campo) da splitfunção string, em vez de apenas "."?
Cbhihe
2
@ CBhihe vê a explicação na minha resposta (que eu cancelei desde que o villapx acha que é útil, graças ao villapx!).
Stephen Kitt