¿Pasar el comando de fecha a una variable?

¿Pasar el comando de fecha a una variable?

Ok, entonces mi problema es el siguiente, deseo pasar esto: -

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

A una variable "a" se le puede agregar una matriz, algo como esto: -

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

La razón por la que estoy haciendo esto es porque me gustaría jugar con 4 dígitos aleatorios (números aleatorios). He producido este script bash para mostrar un ejemplo.

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

Qué salidas: - (Ignore los primeros 9 dígitos)

1622001937610
1622001938249
1622001938758
1622001939267
1622001939774
1622001940282
1622001940790
1622001941299
1622001941807
1622001942315
1622001942823

Ahora quería agregar los resultados de solo una instancia de esto en una matriz, indexar desde el último noveno dígito para recibir 4 dígitos aleatorios según el nano segundo.

Sin embargo, parece que no he comprendido completamente la sintaxis utilizada en bash para lograr el resultado. ¿Podría llamar date +%s%N)/1000000directamente a una matriz? Como mi idea era crear una matriz vacía y luego simplemente agregar el resultado a la matriz e indexar desde el noveno número. Y pasar el resultado a una segunda variable desde allí en la que pueda trabajar.

date +%s%N)/1000000Sería de gran ayuda aprender a convertir el resultado de en una variable.

Perdon por ser un dolor. Cualquier gracias de antemano.

Respuesta1

Mi enfoque inicial fue utilizar el procesamiento de cadenas para que la datesalida obtenga los valores requeridos. La versión aquí usa procesamiento matemático (dividir entre 1000000, módulo 10000) pero te dejé la alternativa comentada.

#!/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

Respuesta2

Puedes usar el${var:offset:length} sintaxis de expansión de parámetrospara extraer una subcadena de un valor:

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

O, como se sugiere, usando /dev/urandom:

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

Leyendo eso en una matriz, usando el 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")

Respuesta3

Si ejecuta date +%s%N, el resultado se verá así:

1622046533072036066
ssssssssssmmmuuunnn

con los dígitos de la derecha indicando las unidades más pequeñas. ( m/ u/ npara mili-/micro-/nanosegundos.)

Si divide eso por 1000000, como $(( ... / 1000000))lo hace, elimina los seis dígitos más a la derecha, dejando solo los segundos y milisegundos.

Esos no son muy aleatorios. Por ejemplo, en su prueba, los números de salida consecutivos aumentan en un 508 algo consistente, que en milisegundos coincide estrechamente con los 0,5 segundos que solicitó.

Es probable que obtengas más valores aleatorios si en su lugarconservólos dígitos más a la derecha y eliminó los primeros, por ejemplo, con el operador de módulo, $(( ... % 1000000)). Aunque es posible que los dígitos más bajos tampoco sean muy aleatorios, si el sistema no tiene relojes con una granularidad lo suficientemente fina.

Si mantiene solo los dígitos bajos, realmente no necesita generar datelos segundos completos, sino que podría usar just +%N, excepto que el valor de nanosegundos siempre se completa con ceros hasta 9 dígitos, y Bash trata los números que comienzan con ceros como octales. , por lo que, por ejemplo, 092345678produciría un error. Agregar un dígito adicional al frente evitaría eso, pero también lo evita agregar el valor de los segundos.

En mi sistema, la diferencia entre los valores de iteraciones consecutivas del siguiente bucle estaba aproximadamente en el rango de 1470000 a 1560000 ns (~ 1,5 ms/iteración), por lo que probablemente no usaría más de cuatro de los dígitos más a la derecha.

#/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

En lugar de aritmética, uno podría simplemente tratar la salida datecomo una cadena y cortar algunos caracteres. Esto dejaría los últimos 4 caracteres:

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

Por otra parte, se podrían considerar otras formas de producir números aleatorios, por ejemplo, shufdesde GNU coreutils, que no se limita simplemente a mezclar, sino que también puede seleccionar valores con repetición. Por ejemplo, esto imprimiría 20 números, de 4 dígitos cada uno:

shuf -i 0000-9999 -r -n 20

o con algunos aros para conseguir relleno con ceros:

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

Puede leer la salida en una matriz con readarray:

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

No es sorprendente shufque sea terriblemente más rápido que realizar un bucle en el shell sobre llamadas a date. También podría utilizar un rango más pequeño, por ejemplo, -i 0-9para obtener números de un solo dígito.

información relacionada