Bash - Sequência de números na mesma linha


20

Conheço o comando seqpara gerar uma sequência de números inteiros, um por linha, mas gostaria de fazer duas perguntas:

  1. É possível escrever os números da sequência na mesma linha?

  2. É possível criar uma string composta da sequência de números separados por um espaço em branco?


O shell trata as novas linhas como espaços como separadores de argumentos. Assim, enquanto seq tem um argumento separador, e uma coisa ainda mais simples de dizer é apenasecho $(seq 1 10)
user3188445

1
@ user3188445, é o operador split + glob fazendo isso (que usa a variável especial IFS que por padrão contém espaço e nova linha, mas pode ser alterada), é separado da palavra tokenização feita pelo shell.
Stéphane Chazelas

Respostas:



21

O GNU sequsa a -sopção separator ( ):

$ seq -s ' ' 1 5
1 2 3 4 5

$ var="$(seq -s ' ' 1 5)"
$ echo "$var"
1 2 3 4 5

1
echo $(seq 5)funciona bem.

13

Portátil para todos os shells e qualquer sistema que tenha seq (como esta pergunta está marcada)

Se o início for 1:

$ echo $(seq 10)
1 2 3 4 5 6 7 8 9 10

De outra forma:

$ echo $(seq 5 10)
5 6 7 8 9 10

Com bc:

$ echo $(echo "for (i=0;i<=1000;i++) i"| bc)

Na festança

echo {1..10}

Nota:

Essa solução de eco funciona se o valor do IFS contiver uma nova linha, o que ocorre por padrão.
Por padrão, o IFS é definido como a sequência <space><tab> <newline> . E é redefinido para cada início limpo do shell. Mas, se você tem alguma preocupação de que isso possa ter mudado em alguns casos extremos, temos várias soluções.

Sob bash, zsh, ksh, use: IFS = $ '\ t \ n' (pule todo o restante desta resposta).


No entanto, a redefinição do valor do IFS sob sh pode ser complexa. Leia os detalhes completos aqui .

Desativar IFS.

$ unset IFS; echo $(seq 5 10)                           #Always work.

sempre funcionará. Desde que não exista um código abaixo (ou scripts filho) que precise de um conjunto IFS, como um script necessário OldIFS="$IFS".

Solução correta.

Usando um truque para sh:

sh -c 'IFS="$(printf " \t\nx")"; IFS="${IFS%x}"; printf "$IFS"|xxd'  # correct.

Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
terdon

1
A maioria das implementações sh ignora o IFS encontrado no ambiente (as exceções são alguns derivados de cinzas, versões muito antigas de alguns shells Bourne e versões recentes de posh). Note que você pode simplesmente fazer IFS='<space><tab><newline>' onde aqueles <space>, <tab>, <newline>são os correspondentes caracteres literais.
Stéphane Chazelas


0
seq 10 |xargs

...ou...

seq 10 |paste -s -

Ambos os comandos acima separarão os números inteiros por espaço em branco. xargso padrão é imitar /bin/echoe, portanto, cada número inteiro é separado por um único espaço. O padrão será o comprimento máximo da linha de comando de 128K. Você pode ajustar isso ...

seq 100000 | xargs -s2093009 | wc -l

... imprime 1. Eu o valor -saqui não é arbitrário - eu o obtive depois de tentar um valor mais alto (que aparentemente funcionou de qualquer maneira), mas depois xargsimprimi a mensagem útil:

-s value should be <2093010

pasteé um dos dois (que eu saiba) utilitários sancionados pelo POSIX para manipular linhas de comprimento arbitrário:

pasteuso do aplicativo de especificação :

A maioria dos utilitários padrão funciona em arquivos de texto . O cututilitário pode ser usado para transformar arquivos com comprimentos de linha arbitrários em um conjunto de arquivos de texto que contêm os mesmos dados. O pasteutilitário pode ser usado para criar (ou recriar) arquivos com comprimentos de linha arbitrários.

arquivos de texto

Um arquivo que contém caracteres organizados em zero ou mais linhas. As linhas não contêm caracteres NUL e nenhuma pode exceder {LINE_MAX}bytes de comprimento, incluindo o \ncaractere ewline. Embora o POSIX.1-2008 não faça distinção entre arquivos de texto e arquivos binários (consulte o padrão ISO C) , muitos utilitários produzem apenas resultados previsíveis ou significativos ao operar em arquivos de texto. Os utilitários padrão que possuem essas restrições sempre especificam arquivos de texto nas seções STDIN ou INPUT FILES .

pasteo padrão é um delimitador de tabulação e, portanto, haverá uma tabulação entre cada número inteiro após o segundo comando. Você pode...

seq 10 |paste -sd ' ' - 

... use a -dopção elimitador para alterar esse comportamento,


seq 10 | xargsfunciona bem, mas por causa dos limites de linha de comando, seq 100000 | xargsemite 5 \nlinhas delimitadas (no meu sistema)
Peter.O

@ Peter.O - paste and cut` são os dois utilitários sancionados pelo POSIX para trabalhar com linhas de comprimento arbitrário. Dito isto, xargs | xargsé uma opção. Ou entãoseq 100000|tr \\n \
mikeserv

Comentários não são para discussão prolongada; esta conversa foi movida para o bate-papo .
terdon

@BinaryZebra - não, não - não como você pensa. Por que não tentar definir $IFSum número? E no bashseu devagar, de qualquer maneira. Na sua resposta, você fala sobre sh- você nem precisa definir $IFSnesse contexto - ele será repassado pelo ambiente se estiver definido lá. E não é mais curto do que o seq 100000|paste -sque é melhor do que o desempenho 5: 1. E pastenão vem com nenhuma dica.
mikeserv

@BinaryZebra - vamos lá, por que eu mentiria? Tenho um perfil de resposta considerável neste site porque gosto de divulgar informações erradas? Ou talvez seja porque eu gosto de ajudar as pessoas e aproveitar o desafio de aprender enquanto o faço? Qual você acha que é mais plausível? Eu gosto $IFS- eu uso o tempo todo -, mas não o uso a menos que eu o defina e você também não deveria. Especialmente, você não deve recomendar a estranhos aleatórios que não conhecem nada melhor que eles deveriam fazê-lo. Não deixe ao acaso - é um programa de computador. É um erro se se comportar inesperadamente - por que permitir isso?
mikeserv
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.