Passando o comando de data para uma variável?

Passando o comando de data para uma variável?

Ok, então meu problema é o seguinte, desejo passar isso: -

echo $(($(date +%s%N)/1000000))

Em uma variável "a" pode ser adicionado a um array, algo assim: -

a=$(($(date +%s%N)/1000000))

A razão pela qual estou fazendo isso é que gostaria de ter 4 dígitos aleatórios para brincar (números aleatórios). Eu produzi este script bash para mostrar um exemplo.

#!/bin/bash
for (( c=0; c<=10; c++))
do
        echo $(($(date +%s%N)/1000000))
        sleep .5
done

Quais saídas: - (Ignore os primeiros 9 dígitos)

1622001937610
1622001938249
1622001938758
1622001939267
1622001939774
1622001940282
1622001940790
1622001941299
1622001941807
1622001942315
1622001942823

Agora eu queria adicionar os resultados de apenas uma instância disso em uma matriz, indexando o último nono dígito para receber 4 dígitos aleatórios com base no nano segundo tempo.

No entanto, parece que não entendi completamente a sintaxe usada no bash para obter o resultado. Eu poderia ligar date +%s%N)/1000000diretamente para um array? Como minha ideia era criar um array vazio e depois anexar o resultado ao array e indexar a partir do 9º número. E passe o resultado para uma segunda variável a partir daí na qual eu possa trabalhar.

Apenas aprender a transformar o resultado date +%s%N)/1000000em uma variável já seria de grande ajuda.

Desculpe ser um incômodo. Qualquer agradecimento antecipado.

Responder1

Minha abordagem inicial foi usar o processamento de strings para a datesaída obter os valores necessários. A versão aqui usa processamento matemático (dividir por 1000000, módulo 10000) mas deixei a alternativa comentada para vocês

#!/bin/bash
items=()

random=$(( ($(date +%s%N) / 1000000) % 10000 ))        # Second and milliseconds
# random=$( date +%s%N | grep -oP '....(?=......$)' )

items+=($random)                                       # Append value to array

echo "${items[0]}"                                     # First array value
echo "${items[-1]}"                                    # Last (most recently appended) value
declare -p items                                       # Visual inspection of array elements

Responder2

Você pode usar o${var:offset:length} sintaxe de expansão de parâmetropara extrair uma substring de um valor:

$ nanoseconds=$(date +%N)
$ printf '%s\n' "$nanoseconds" "${nanoseconds:2:4}"
785455000
5455

Ou, como sugerido, usando /dev/urandom:

$ tr -dc '[:digit:]' < /dev/urandom | fold -w 4 | head -n 10
8386
9194
3897
8790
4738
1453
4323
9021
6033
8889

Lendo isso em um array, usando o mapfilecomando bash:

$ mapfile -t numArray < <(tr -dc '[:digit:]' < /dev/urandom | fold -w 4 | head -n 10)
$ declare -p numArray
declare -a numArray=([0]="2851" [1]="9684" [2]="5823" [3]="5206" [4]="3208" [5]="2914" [6]="0395" [7]="4128" [8]="1876" [9]="5691")

Responder3

Se você executar date +%s%N, a saída será semelhante a esta:

1622046533072036066
ssssssssssmmmuuunnn

com os dígitos da direita indicando as unidades menores. ( m/ u/ npara milis/micro/nanossegundos.)

Se você dividir isso por 1.000.000, como $(( ... / 1000000))faz, você remove os seis dígitos mais à direita, deixando apenas os segundos e milissegundos.

Isso não é muito aleatório. Por exemplo, em sua execução de teste, os números de saída consecutivos aumentam em 508 um tanto consistente, que em milissegundos corresponde aproximadamente aos 0,5 segundos solicitados.

Você provavelmente obteria mais valores aleatórios se, em vez disso,mantidoos dígitos mais à direita e eliminou os primeiros, por exemplo, com o operador de módulo, $(( ... % 1000000)). Embora seja possível que os dígitos mais baixos também não sejam muito aleatórios, se o sistema não tiver relógios com granularidade suficientemente fina.

Se você mantiver apenas os dígitos baixos, você realmente não precisa gerar dateos segundos completos, mas pode usar apenas +%N, exceto que o valor dos nanossegundos é sempre preenchido com zeros até 9 dígitos, e o Bash trata os números começando com zeros como octais , então, por exemplo, 092345678produziria um erro. Adicionar um dígito extra à frente evitaria isso, mas o mesmo acontece com a adição do valor dos segundos.

No meu sistema, a diferença entre os valores de iterações consecutivas do loop a seguir estava aproximadamente na faixa de 1470000 a 1560000 ns (~ 1,5 ms/iteração), então provavelmente não usaria mais do que quatro dos dígitos mais à direita.

#/bin/bash
array=()
prev=$(date +%s%N)
for ((i=0; i < 100; i++)); do 
        this=$(date +%s%N)
        # diff=$(( (this - prev) % 1000000000))
        diff=$(( (this - prev) % 10000))
        printf "$prev $this %04d\n" "$diff"
        array+=("$diff")
        prev=$this
done

Em vez de aritmética, pode-se simplesmente tratar a saída datecomo uma string e cortar alguns caracteres. Isso deixaria os últimos 4 caracteres:

a=$(date +%N)
a=${a: -4}

Então, novamente, poderíamos considerar outras maneiras de produzir números aleatórios, por exemplo, shufa partir do GNU coreutils, que não se limita apenas a embaralhar, mas também pode escolher valores com repetição. Por exemplo, isso imprimiria 20 números, 4 dígitos cada:

shuf -i 0000-9999 -r -n 20

ou com alguns aros para obter preenchimento zero:

shuf -i 10000-19999 -r -n 20 |sed -e 's/^1//'

Você pode ler a saída para um array com readarray:

readarray array < <(shuf -i 0000-9999 -r -n 20)

Não é de surpreender shufque seja terrivelmente mais rápido do que fazer um loop no shell por meio de chamadas para date. Você também pode usar um intervalo menor, por exemplo, -i 0-9para obter números de um único dígito.

informação relacionada