Converter string "1-5" em array de números em bash


3

Qual é a melhor abordagem para converter a string contendo o intervalo de números em números em si? Esse formato é usado, por exemplo, na definição do intervalo de páginas a serem impressas. Eu defino, eu quero imprimir essas páginas "11-14,17,20" . Agora eu preciso escrever o script bash que irá alterar essa string na matriz de números: 11, 12, 13, 14, 17, 20

Ele deve ser capaz de trabalhar com strings que contenham números (mesmo com mais dígitos) e com ',' e '-'.


@Flimzy - Eu tentei usar sed - para dividir a string em linhas sempre que o caracter '-' for encontrado. E, em seguida, olhar para o último número da linha anterior e a primeira linha da linha real e fazer para o ciclo com o incremento ... Um pouco complicado caminho :)
srnka

Sim, sed pode funcionar, com outro código de suporte suficiente. Perl é muito mais poderoso e, portanto, mais conciso (se não for feio) para esse tipo de coisa, se você estiver disposto a usar o perl, como a minha resposta abaixo sugere.
Flimzy

Respostas:


3

Isso faz isso em Perl:

echo 11-14,17,20 | perl -pe 's/(\d+)-(\d+)/join(",",$1..$2)/eg'

Saída:

11,12,13,14,17,20

2
Eu não posso nem ler isso! Perl realmente mantém seu nome como uma linguagem somente leitura ...
sinni800

Muito boa solução, em uma linha :) E funciona bem para mim! Mas eu não posso usar o perl - o script final deve ser independente do perl.
srnka

Isso funciona mais confiável para o meu sistema embarcado. Eu vou usar isso. Obrigado :)
srnka

Ah, então você pode usar perl depois de tudo? Agradável :)
Flimzy

3

Aqui está uma solução usando awk:

#!/bin/bash

pages="11-14,17,20"

echo $pages | awk 'BEGIN { RS=","; FS="-"; ORS="" }
  NR > 1  { print "," }
  NF > 1  { for (i=$1; i<$2; ++i) { print i "," } print $2; next }
          { print $1 }'

Isso resulta na seguinte saída:

11,12,13,14,17,20


Obrigado - é só o que eu estava procurando. Mas como isso funciona? Quando eu quero converter o intervalo 11-14, a saída é: 11,12,13,14,14 O último é dobrado. E eu não posso corrigi-lo.
srnka

Hmm, eu não consigo reproduzir isso sozinho. Eu tentei com o GNU awk 4.0.0 e com o GNU awk 3.1.5, assim como com as instalações padrão do awk no OpenBSD e no Mac OSX, e tudo parece funcionar bem. Qual sistema operacional e awk você está usando?
Kusalananda

@ Srnka, você redigitou meu código e esqueceu o next? Copie e cole em seu lugar.
Kusalananda

Sim, poderia haver um problema - eu usá-lo no Linux incorporado, o awk é uma parte do pacote busybox: BusyBox v1.18.4 (2011-06-22 18:48:08 CEST) multi-call binário.
srnka

Eu tenho um problema com o intervalo que contém o número 9, mas parece ser um bug no awk do busybox .. Só para info :)
srnka

2

Apenas bash:

expand_ranges() {
  local IFS=,
  set -- $1
  for range; do
    case $range in 
      *-*) for (( i=${range%-*}; i<=${range#*-}; i++ )); do echo $i; done ;;
      *)   echo $range ;;
    esac
  done
}
numbers=( $(expand_ranges 11-14,17,20) )

Para sua saída solicitada: IFS=,; echo ${numbers[*]}


Não funciona para mim. Apenas escreve o primeiro número e termina. Eu uso o GNU bash, versão 3.2.39 (1)
srnka

isso é porque "números" é na verdade uma matriz, como você solicitou. Usar ${numbers[@]} para imprimir todo o conteúdo da matriz.
glenn jackman

0

Se você tem jot do seu sistema

Exemplo de uso de jot e sed é (não se esqueça nova linha caractere em seqüência de substituição!):

$echo 1-2,3,6-9| sed 's/,/\
/g'|sed -E '/-/s/([0-9]+)-([0-9]+)/- \1 \2/g;s/^([0-9]+)$/- \1 \1/g'| xargs -L 1 jot | rs -t -C,
1,2,3,6,7,8,9

Se você digitar echo jot em vez de "jot" (e remova rs chamada) você deve ver a seguinte saída:

jot - 1 2
jot - 3 3
jot - 6 9

Eu editei minha resposta
Eir Nym

0

Essa é uma maneira meio lisp de fazer as coisas (exceto pelo fato de que bash não gosta de listas preguiçosas, então temos que definir um limite superior no número máximo de páginas; aqui eu escolhi 10000)

pages="11-14,17,20"; for ((i=1;i<10000;i++)); do echo -n $i, ; done | cut -d , -f $pages

Com as páginas, você especifica o intervalo de páginas como na outra postagem. O loop for gera uma lista de números de páginas. Desses, o comando cut seleciona os que você quer.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.