Создать случайное имя файла в оболочке unix

Я хотел бы создать случайное имя файла в оболочке unix (скажем, tcshell). Имя файла должно состоять из случайных 32 шестнадцатеричные цифры, например:

c7fdfc8f409c548a10a0a89a791417c5

(к которому я добавлю, что необходимо). Дело в том, что это можно сделать только в оболочке, не прибегая к программе.

12 ответов


предполагая, что вы находитесь на linux, должно работать следующее:

cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32

это только псевдослучайно, если ваша система работает с низкой энтропией, но (в linux) гарантированно завершится. Если вам нужны действительно случайные данные, кот /dev/random вместо /dev/urandom. Это изменение сделает ваш код блоком до тех пор, пока не будет достаточно энтропии для получения действительно случайного вывода, поэтому это может замедлить ваш код. Для большинства применений вывод /dev/urandom - Это достаточно случайный.

если вы в OS X или другом BSD вам нужно изменить его следующим образом:

cat /dev/urandom | env LC_CTYPE=C tr -cd 'a-f0-9' | head -c 32

почему не использовать команду unix mktemp:

$ TMPFILE=`mktemp tmp.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` &&  echo $TMPFILE
tmp.MnxEsPDsNUjrzDIiPhnWZKmlAXAO8983

одна команда, отсутствие трубы, отсутствие петли:

hexdump -n 16 -v -e '/1 "%02X"' -e '/16 "\n"' /dev/urandom

Если вам не нужна новая строка, например, когда вы используете ее в переменной:

hexdump -n 16 -v -e '/1 "%02X"' /dev/urandom

использование "16" генерирует 32 шестнадцатеричные цифры.


протестировано в zsh, должно работать с любой совместимой оболочкой BASH!

#!/bin/zsh

SUM=`md5sum <<EOF
$RANDOM
EOF`

FN=`echo $SUM | awk '// { print  }'`

echo "Your new filename: $FN"

пример:

$ zsh ranhash.sh
Your new filename: 2485938240bf200c26bb356bbbb0fa32
$ zsh ranhash.sh
Your new filename: ad25cb21bea35eba879bf3fc12581cc9

как вы, вероятно, заметили из каждого из ответов, вы вообще есть "прибегнуть к программе".

однако, без использования любые внешние исполняемые файлы, в Баш и КШ:

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, распределение цифр с помощью фрагментов может быть искажено (не говоря уже о том, что числа псевдо random в первую очередь). Однако, поскольку мы используем mod 16 и 32768 делится на 16, это не будет проблемой здесь.

в любом случае, правильный способ сделать это с помощью mktemp а в Олега Разгуляева ответ.


этот ответ очень похож на fmarks, поэтому я не могу взять на себя ответственность за это, но я нашел комбинации команд cat и tr довольно медленными, и я нашел эту версию немного быстрее. Вам необходимо вывести.

hexdump -e '/1 "%02x"' -n32 < /dev/urandom

еще один способ[tm].

R=$(echo $RANDOM $RANDOM $RANDOM $RANDOM $RANDOM | md5 | cut -c -8)
FILENAME="abcdef-$R"

возьмите 16 байт из /dev/random, преобразовать их в шестнадцатеричные, взять первую строку, удалить адрес, удалить пробелы.

head /dev/random -c16 | od -tx1 -w16 | head -n1 | cut -d' ' -f2- | tr -d ' '

предполагая, что "без обращения к программе" означает "использование только программ, которые легко доступны", конечно.


Если вы находитесь в Linux, то Python будет предварительно установлен. Таким образом, вы можете пойти на что-то похожее на ниже:

python -c "import uuid; print str(uuid.uuid1())"

Если вам не нравятся тире, используйте функцию замены, как показано ниже

python -c "import uuid; print str(uuid.uuid1()).replace('-','')"

первый ответ хорош, но почему вилка cat, если это не требуется.

tr -dc 'a-f0-9' < /dev/urandom | head -c32

надеюсь добавить (возможно) лучшее решение для этой темы.

обратите внимание: это работает только с bash4 и некоторые реализации mktemp(например, GNU one)

попробуй такое

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

еще одна вещь, которую вы можете добавить, - это выполнить команду date следующим образом:

date +%S%N

считывает время nonosecond и результат добавляет много рандома.