Datumsbefehl an eine Variable übergeben?

Datumsbefehl an eine Variable übergeben?

Ok, also mein Problem ist folgendes, ich möchte Folgendes weitergeben: -

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

In eine Variable „a“, um sie einem Array hinzuzufügen, etwa so: -

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

Der Grund, warum ich das mache, ist, dass ich gerne 4 Zufallszahlen hätte, mit denen ich spielen könnte (Zufallszahlen). Ich habe dieses Bash-Skript erstellt, um ein Beispiel zu zeigen.

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

Welche Ausgaben: - (Ignorieren Sie die ersten 9 Ziffern)

1622001937610
1622001938249
1622001938758
1622001939267
1622001939774
1622001940282
1622001940790
1622001941299
1622001941807
1622001942315
1622001942823

Jetzt wollte ich die Ergebnisse von nur einer Instanz davon in ein Array einfügen, mit dem Index ab der letzten 9. Ziffer, um 4 zufällige Ziffern basierend auf der Nanosekundenzeit zu erhalten.

Allerdings habe ich die Syntax, die in Bash verwendet wird, um das Ergebnis zu erzielen, anscheinend nicht ganz verstanden. Könnte ich möglicherweise date +%s%N)/1000000direkt ein Array aufrufen? Meine Idee war, ein leeres Array zu erstellen und dann einfach das Ergebnis an das Array anzuhängen und ab der 9. Zahl zu indexieren. Und das Ergebnis an eine zweite Variable zu übergeben, mit der ich von dort aus arbeiten kann.

Allein zu lernen, das Ergebnis in eine Variable umzuwandeln, date +%s%N)/1000000wäre eine große Hilfe.

Tut mir leid, dass ich lästig bin. Vielen Dank im Voraus.

Antwort1

Mein ursprünglicher Ansatz bestand darin, die Ausgabe mit einer Zeichenfolgenverarbeitung zu versehen, dateum die gewünschten Werte zu erhalten. Die Version hier verwendet eine mathematische Verarbeitung (Division durch 1000000, Modulo 10000), aber ich habe die Alternative für Sie kommentiert gelassen.

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

Antwort2

Du kannst den ... benutzen${var:offset:length} Syntax der Parametererweiterungum eine Teilzeichenfolge eines Wertes zu extrahieren:

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

Oder, wie vorgeschlagen, mit /dev/urandom:

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

Das Einlesen in ein Array mithilfe des Bash- mapfileBefehls:

$ 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")

Antwort3

Wenn Sie ausführen date +%s%N, sieht die Ausgabe ungefähr so ​​aus:

1622046533072036066
ssssssssssmmmuuunnn

wobei die Ziffern auf der rechten Seite die kleineren Einheiten angeben. ( m/ u/ nfür Milli-/Mikro-/Nanosekunden.)

Wenn Sie diesen Wert wie $(( ... / 1000000))beschrieben durch 1.000.000 teilen, entfernen Sie die sechs Ziffern ganz rechts und es bleiben nur die Sekunden und Millisekunden übrig.

Diese sind nicht sehr zufällig. Beispielsweise erhöhen sich in Ihrem Testlauf die aufeinanderfolgenden Ausgabezahlen um einigermaßen konstante 508, was in Millisekunden genau den von Ihnen angeforderten 0,5 Sekunden entspricht.

Sie würden wahrscheinlich mehr Zufallswerte erhalten, wenn Sie stattdessengehaltendie Ziffern ganz rechts und die führenden weggelassen, z. B. mit dem Modulo-Operator $(( ... % 1000000)). Es ist jedoch möglich, dass auch die niedrigsten Ziffern nicht sehr zufällig sind, wenn das System keine Uhren mit ausreichend feiner Granularität hat.

Wenn Sie nur die unteren Ziffern behalten, müssen Sie nicht unbedingt datedie gesamten Sekunden ausgeben, sondern können stattdessen einfach verwenden +%N, allerdings wird der Nanosekundenwert immer mit Nullen auf 9 Ziffern aufgefüllt und Bash behandelt Zahlen, die mit Nullen beginnen, als Oktalzahlen, sodass zB 092345678einen Fehler erzeugen würde. Das Hinzufügen einer zusätzlichen Ziffer am Anfang würde das verhindern, aber das Hinzufügen des Sekundenwerts tut dies auch.

Auf meinem System lag der Unterschied zwischen den Werten aus aufeinanderfolgenden Iterationen der folgenden Schleife ungefähr im Bereich von 1.470.000 bis 1.560.000 ns (~ 1,5 ms/Iteration), daher würde ich wahrscheinlich nicht mehr als vier der äußersten rechten Ziffern verwenden.

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

Anstatt zu rechnen, könnte man die Ausgabe einfach dateals Zeichenfolge behandeln und einige Zeichen abschneiden. Dadurch blieben die letzten 4 Zeichen übrig:

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

Andererseits könnte man andere Möglichkeiten zur Erzeugung von Zufallszahlen in Betracht ziehen, z. B. shufGNU Coreutils, die nicht nur auf das Mischen beschränkt sind, sondern auch Werte durch Wiederholung auswählen können. Dies würde z. B. 20 Zahlen mit jeweils 4 Ziffern ausgeben:

shuf -i 0000-9999 -r -n 20

oder mit ein paar Tricks, um Null-Padding zu erhalten:

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

Sie können die Ausgabe mit folgendem Befehl in ein Array lesen readarray:

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

Es überrascht nicht, dass shufdies schrecklich schneller ist als das Durchlaufen der Shell über Aufrufe von date. Sie können auch einen kleineren Bereich verwenden, -i 0-9um beispielsweise einstellige Zahlen zu erhalten.

verwandte Informationen