Итак, моя проблема заключается в следующем. Я хочу передать это:
echo $(($(date +%s%N)/1000000))
В переменную «a» ее можно добавить в массив, что-то вроде этого:-
a=$(($(date +%s%N)/1000000))
Причина, по которой я это делаю, заключается в том, что мне нужны 4 случайные цифры для игры (случайные числа). Я создал этот скрипт bash, чтобы показать пример.
#!/bin/bash
for (( c=0; c<=10; c++))
do
echo $(($(date +%s%N)/1000000))
sleep .5
done
Что выводит: (Игнорируйте первые 9 цифр)
1622001937610
1622001938249
1622001938758
1622001939267
1622001939774
1622001940282
1622001940790
1622001941299
1622001941807
1622001942315
1622001942823
Теперь я хотел бы добавить результаты только одного экземпляра этого массива, индексируя последнюю 9-ю цифру, чтобы получить 4 случайные цифры на основе наносекундного времени.
Однако я, похоже, не полностью понял синтаксис, используемый в bash для достижения результата. Могу ли я вызвать его date +%s%N)/1000000
напрямую в массив? Поскольку моя идея была создать и очистить массив, а затем просто добавить результат в массив и индексировать с 9-го числа. И передать результат во вторую переменную, оттуда я могу работать.
Было бы очень полезно просто научиться преобразовывать результат date +%s%N)/1000000
в переменную.
Извините за беспокойство. Спасибо заранее.
решение1
Мой первоначальный подход заключался в использовании обработки строк для date
вывода, чтобы получить требуемые значения. Версия здесь использует математическую обработку (деление на 1000000, остаток 10000), но я оставил альтернативу в комментариях для вас
#!/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
решение2
Вы можете использовать${var:offset:length}
синтаксис расширения параметровдля извлечения подстроки значения:
$ nanoseconds=$(date +%N)
$ printf '%s\n' "$nanoseconds" "${nanoseconds:2:4}"
785455000
5455
Или, как предлагается, используя /dev/urandom:
$ tr -dc '[:digit:]' < /dev/urandom | fold -w 4 | head -n 10
8386
9194
3897
8790
4738
1453
4323
9021
6033
8889
Считываем это в массив, используя mapfile
команду 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")
решение3
Если вы запустите date +%s%N
, вывод будет выглядеть примерно так:
1622046533072036066
ssssssssssmmmuuunnn
с правыми цифрами, указывающими меньшие единицы. ( m
/ u
/ n
для милли-/микро-/наносекунд.)
Если вы разделите это число на 1000000, как $(( ... / 1000000))
это делается, вы удалите шесть крайних правых цифр, оставив только секунды и миллисекунды.
Они не очень случайны. Например, в вашем тестовом прогоне последовательные выходные числа увеличиваются на довольно постоянные 508, что в миллисекундах близко соответствует запрошенным вами 0,5 секундам.
Вы, скорее всего, получите больше случайных значений, если вместо этогосохранилсамые правые цифры и отбрасываем ведущие, например, с помощью оператора по модулю, $(( ... % 1000000))
. Хотя возможно, что и самые младшие цифры не очень случайны, если в системе нет часов с достаточно высокой степенью детализации.
Если вы сохраните только нижние цифры, вам не нужно выводить date
полные секунды, но вместо этого можно использовать просто +%N
, за исключением того, что значение наносекунд всегда дополняется нулями до 9 цифр, а Bash обрабатывает числа, начинающиеся с нулей, как восьмеричные, поэтому eg 092345678
приведет к ошибке. Добавление дополнительной цифры в начало предотвратит это, но то же самое делает и добавление значения секунд.
В моей системе разница между значениями из последовательных итераций следующего цикла составляла примерно от 1470000 до 1560000 нс (~ 1,5 мс / итерация), поэтому я, вероятно, не стал бы использовать более четырех крайних правых цифр.
#/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
Вместо арифметики можно было бы просто обработать вывод date
как строку и отсечь некоторые символы. Это оставило бы последние 4 символа:
a=$(date +%N)
a=${a: -4}
С другой стороны, можно рассмотреть другие способы получения случайных чисел, например, shuf
из GNU coreutils, который не ограничивается только перемешиванием, но также может выбирать значения с повторением. Например, это выведет 20 чисел, по 4 цифры каждое:
shuf -i 0000-9999 -r -n 20
или с некоторыми ухищрениями, чтобы получить дополнение нулями:
shuf -i 10000-19999 -r -n 20 |sed -e 's/^1//'
Вы можете прочитать вывод в массив с помощью readarray
:
readarray array < <(shuf -i 0000-9999 -r -n 20)
Неудивительно, shuf
что это ужасно быстрее, чем цикл в оболочке по вызовам date
. Вы также можете использовать меньший диапазон, например, -i 0-9
для получения однозначных чисел.