Создание произвольного имени файла в оболочке unix
Я хотел бы создать случайное имя файла в оболочке unix (скажем, tcshell). Имя файла должно состоять из случайных 32 шестнадцатеричных букв, например:
c7fdfc8f409c548a10a0a89a791417c5
(к которому я добавлю все, что необходимо). Дело в том, что это можно сделать только в оболочке, не прибегая к программе.
Ответы
Ответ 1
Предполагая, что вы работаете в Linux, должно работать следующее:
cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32
Это только псевдослучайное, если ваша система работает на энтропии, но она (на linux) гарантированно завершается. Если вам нужны действительно случайные данные, cat /dev/random
вместо /dev/urandom
. Это изменение сделает ваш блок кода до тех пор, пока не будет достаточно энтропии для создания действительно случайного вывода, поэтому он может замедлить ваш код. Для большинства применений вывод /dev/urandom
достаточно случайный.
Если вы используете OS X или другой BSD, вам необходимо изменить его на следующее:
cat /dev/urandom | env LC_CTYPE=C tr -cd 'a-f0-9' | head -c 32
Ответ 2
почему не используйте команду unix mktemp:
$ TMPFILE=`mktemp tmp.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` && echo $TMPFILE
tmp.MnxEsPDsNUjrzDIiPhnWZKmlAXAO8983
Ответ 3
Одна команда, ни один канал, ни петли:
hexdump -n 16 -v -e '/1 "%02X"' -e '/16 "\n"' /dev/urandom
Если вам не нужна новая строка, например, когда вы используете ее в переменной:
hexdump -n 16 -v -e '/1 "%02X"' /dev/urandom
Использование "16" генерирует 32 шестнадцатеричных цифры.
Ответ 4
Как вы, наверное, заметили по каждому из ответов, вам обычно приходится "прибегать к программе".
Однако без использования внешних исполняемых файлов в Bash и ksh:
string=''; for i in {0..31}; do string+=$(printf "%x" $(($RANDOM%16)) ); done; echo $string
в зш:
string=''; for i in {0..31}; do string+=$(printf "%x" $(($RANDOM%16)) ); dummy=$RANDOM; done; echo $string
Измените нижний регистр x
в строке формата на верхний регистр X
чтобы сделать буквенные шестнадцатеричные символы заглавными.
Вот еще один способ сделать это в Bash, но без явного цикла:
printf -v string '%X' $(printf '%.2s ' $((RANDOM%16))' '{00..31})
В дальнейшем "первый" и "второй" printf
относятся к порядку, в котором они выполняются, а не к порядку, в котором они появляются в строке.
Этот метод использует расширение фигурных скобок для создания списка из 32 случайных чисел mod 16, за которым следует пробел и одно из чисел в диапазоне в фигурных скобках, за которым следует другой пробел (например, 11 00
). Для каждого элемента этого списка первый printf
удаляет все, кроме первых двух символов, используя свою строку формата (%.2
), оставляя либо одну цифру, а затем пробел или две цифры. Пробел в строке формата гарантирует, что между каждым выходным номером будет хотя бы один пробел.
Подстановка команд, содержащая первый printf
, не заключена в кавычки, поэтому выполняется разбиение слов, и каждое число передается второму printf
в качестве отдельного аргумента. Там числа преобразуются в шестнадцатеричный формат с помощью строки формата %X
и добавляются друг к другу без пробелов (поскольку в строке формата их нет), а результат сохраняется в переменной с именем string
.
Когда printf
получает больше аргументов, чем учитывается в строке формата, формат применяется к каждому аргументу по очереди, пока все они не будут использованы. Если аргументов меньше, несоответствующая строка формата (часть) игнорируется, но это не применимо в этом случае.
Я проверял это в Bash 3.2, 4.4 и 5.0-alpha. Но это не работает в zsh (5.2) или ksh (93u+), потому что RANDOM
оценивается только один раз в расширении скобок в этих оболочках.
Обратите внимание, что из-за использования оператора mod для значения, которое находится в диапазоне от 0 до 32767, распределение цифр с использованием фрагментов может быть искажено (не говоря уже о том, что числа являются псевдослучайными в первую очередь). Однако, так как мы используем мод 16 и 32768 делится на 16, это не будет проблемой здесь.
В любом случае, правильный способ сделать это - использовать mktemp
как в ответе Олега Разгуляева.
Ответ 5
Протестировано в zsh, должно работать с любой совместимой оболочкой BASH!
#!/bin/zsh
SUM=`md5sum <<EOF
$RANDOM
EOF`
FN=`echo $SUM | awk '// { print $1 }'`
echo "Your new filename: $FN"
Пример:
$ zsh ranhash.sh
Your new filename: 2485938240bf200c26bb356bbbb0fa32
$ zsh ranhash.sh
Your new filename: ad25cb21bea35eba879bf3fc12581cc9
Ответ 6
Еще один способ [tm].
R=$(echo $RANDOM $RANDOM $RANDOM $RANDOM $RANDOM | md5 | cut -c -8)
FILENAME="abcdef-$R"
Ответ 7
Этот ответ очень похож на fmarks, поэтому я не могу поверить в это, но я нашел команды кота и tr команд довольно медленными, и я нашел эту версию довольно быстро. Вам нужен hexdump.
hexdump -e '/1 "%02x"' -n32 < /dev/urandom
Ответ 8
Первый ответ хороший, но зачем вилка, если кошка не требуется.
tr -dc 'a-f0-9' < /dev/urandom | head -c32
Ответ 9
Захватите 16 байтов из /dev/random
, преобразуйте их в шестнадцатеричный, возьмите первую строку, удалите адрес, удалите пробелы.
head /dev/random -c16 | od -tx1 -w16 | head -n1 | cut -d' ' -f2- | tr -d ' '
Предполагая, что "не прибегая к программе" означает "использование только программ, которые легко доступны", конечно.
Ответ 10
Надеемся добавить (возможно) лучшее решение этой темы.
Обратите внимание: это работает только с bash4
и некоторыми реализациями mktemp
(например, GNU)
Попробуйте это
fn=$(mktemp -u -t 'XXXXXX')
echo ${fn/\/tmp\//}
Это вдвое быстрее, чем head /dev/urandom | tr -cd 'a-f0-9' | head -c 32
, и в восемь раз быстрее, чем cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32
.
Benchmark:
С помощью mktemp:
#!/bin/bash
# a.sh
for (( i = 0; i < 1000; i++ ))
do
fn=$(mktemp -u -t 'XXXXXX')
echo ${fn/\/tmp\//} > /dev/null
done
time ./a.sh
./a.sh 0.36s user 1.97s system 99% cpu 2.333 total
И другое:
#!/bin/bash
# b.sh
for (( i = 0; i < 1000; i++ ))
do
cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 32 > /dev/null
done
time ./b.sh
./b.sh 0.52s user 20.61s system 113% cpu 18.653 total
Ответ 11
Если вы находитесь в Linux, то Python будет установлен заранее. Таким образом, вы можете найти что-то похожее на следующее:
python -c "import uuid; print str(uuid.uuid1())"
Если вам не нравятся тире, используйте функцию замены, как показано ниже
python -c "import uuid; print str(uuid.uuid1()).replace('-','')"
Ответ 12
Еще одна вещь, которую вы можете добавить, - это запустить команду date следующим образом:
date +%S%N
Считывает односекундное время, и результат добавляет много случайности.
Ответ 13
Если у вас есть openssl
в вашей системе, вы можете использовать его для генерации случайных шестнадцатеричных (также это может быть -base64
) строк определенной длины. Я нашел это довольно простым и удобным в работе cron в одной строке.
openssl rand -hex 32
8c5a7515837d7f0b19e7e6fa4c448400e70ffec88ecd811a3dce3272947cb452
Ответ 14
uuidgen
генерирует именно это, за исключением того, что вы должны удалить дефисы. Поэтому я считаю, что это самый элегантный (по крайней мере для меня) способ достижения этого. Он должен работать на Linux и OS X из коробки.
uuidgen | tr -d '-'