Створення випадкового імені файлу в оболонці unix


76

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

c7fdfc8f409c548a10a0a89a791417c5

(до якого я додаю все необхідне). Справа в тому, що це можна робити лише в оболонці, не вдаючись до програми.


Відповіді:


126

Припускаючи, що ви використовуєте 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

1
@LukeN: Твоє було добре. І технічно це рішення не гарантовано припиняється :)
Президент Джеймс К. Полк

1
Це рішення насправді робило для мене дивні речі, оскільки додало знак із білим фоном "%" після фактичного випадкового хешу, але оскільки моя оболонка, як правило, поводиться дивно в деяких випадках, я не хотів, щоб це виглядало погано це було прийнято :)
LukeN

1
Я спробував це на Mac, який має / dev / urandom. Виконання команди в оболонці bash викликає помилку - 'tr: Нелегальна послідовність байтів'
Gareth Stockwell

5
Я думаю, що проблема тут полягає в тому, що BSD та Mac інтерпретують рядок як багатобайтовий, а не однобайтовий. У мене немає машини, щоб спробувати це, тому повідомте сюди, якщо це працює: cat / dev / urandom | env LC_CTYPE = C tr -cd 'a-f0-9' | head -c 32
fmark

2
Схоже на чергове марне використання кота :-)
Йенс,

42

чому не використовувати команду unix mktemp:

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

5
У цьому випадку ви не тільки згенеруєте рядок, але й створите файл.
Ігор Чубін

5
деякі реалізації мають --dry-runпрапор, який запобігає створенню файлу. Це, звичайно, відкриває можливі умови змагання.
glenn jackman

21

Одна команда, без каналу, без циклу:

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

Якщо вам не потрібен новий рядок, наприклад, коли ви використовуєте його у змінній:

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

Використання "16" генерує 32 шістнадцяткові цифри.


Це круто. Я ніколи не думав використовувати hexdumpдля цього.
avetisk

7

Як ви, мабуть, помітили з кожної з відповідей, ви, як правило, маєте "вдаватися до програми".

Однак, не використовуючи зовнішніх виконуваних файлів , в Bash і ksh:

string=''; for i in {0..31}; do string+=$(printf "%x" $(($RANDOM%16)) ); done; echo $string

в zsh:

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 випадкових чисел мод 16, кожному з яких слід пробіл та одне з чисел у діапазоні в фігурних дужках, після чого інший пробіл (наприклад 11 00). Для кожного елемента цього списку перший printfвидаляє всі символи, крім перших двох, за допомогою його рядка формату (%.2 ), залишаючи одну цифру, а потім пробіл кожну або дві цифри. Пробіл у рядку формату гарантує, що тоді між кожним вихідним номером є принаймні один пробіл.

Заміна команди, що містить першу printf, не цитується, тому виконується розбиття слів, і кожне число переходить до другого printfяк окремий аргумент. Там числа перетворюються у шістнадцяткові за допомогою %Xрядка формату, і вони додаються одне до одного без пробілів (оскільки їх у рядку формату немає), а результат зберігається у змінній з іменемstring .

Коли printfотримує більше аргументів, ніж для його рядка формату, формат по черзі застосовується до кожного аргументу, поки всі вони не будуть спожиті. Якщо аргументів менше, нерівний рядок формату (частина) ігнорується, але в цьому випадку це не застосовується.

Я тестував його в Bash 3.2, 4.4 та 5.0-alpha. Але це не працює у zsh (5.2) або ksh (93u +), тому що RANDOMоцінюється лише один раз при розгортанні фігурної дужки в цих оболонках.

Зверніть увагу, що через використання оператора мода для значення, яке варіюється від 0 до 32767, розподіл цифр за допомогою фрагментів може бути перекошеним (не кажучи вже про те, що числа в першу чергу є псевдовипадковими ). Однак, оскільки ми використовуємо мод 16 і 32768, ділиться на 16, це не буде проблемою тут.

У будь-якому випадку, правильним способом цього є використання, mktempяк у відповіді Олега Разгуляєва .


1
Дякую Деннісе, це мені допомогло .. Я просто встановив рядок порожнім, так що довжина рядка завжди буде такою, як очікувалося, що додається кожного разу під час повторного запуску того самого сценарію .. randomId = $ (string = ""; for i у {0..5}; зробіть рядок + = $ (printf "% x" $ (($ RANDOM% 16))); готово; повторіть $ рядок); echo "Значення випадкового ідентифікатора - $ {randomId}"
Сантош Кумар Арджунан

@SantoshKumarA: Дякуємо, що вказали, що змінну потрібно ініціалізувати. Я додав це до своєї відповіді. Я також додаю ще одну цікаву техніку та пояснення до неї.
Денніс Вільямсон

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

1
Це створить лише 32768 унікальних імен файлів, а не 16^32.
Денніс Вільямсон

Це також буде працювати лише в системах, які включають md5sumдвійковий файл. Наприклад, FreeBSD та OSX мають a, /sbin/md5який виконує одну і ту ж мету, але використовує інший синтаксис опцій.
ghoti

4

Ще один спосіб [тм].

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

програма, доступна для більшості систем, - md5sum. Мені подобається це рішення, тому що якщо вам не потрібна висока випадковість, ви можете просто використовувати $ RANDOM лише один раз, роблячи це найкоротшим та найбільш читабельним рішенням.

а) Якщо у вас є md5sum, ви можете замінити md5 на md5sum і відповідно оновити виріз. б) Використовувати лише один $ RANDOM небезпечно, він створює лише значення від 0 до 32767, що значно менше, залежно від програми.
рето

3

Ця відповідь дуже схожа на fmarks, тому я не можу похвалитися цим, але я знайшов комбінації команд cat і tr досить повільними, і я знайшов цю версію трохи швидше. Вам потрібен hexdump.

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

Туз. Використовуйте -n16з 32 символів.
Уолф,

3

Перша відповідь хороша, але навіщо виделка коту, якщо не потрібно.

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

2

uuidgenгенерує саме це, за винятком того, що вам доведеться видаляти дефіси. Тож я виявив, що це найелегантніший (принаймні для мене) спосіб досягнення цього. Це має працювати на Linux та OS X нестандартно.

uuidgen | tr -d '-'

1

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

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

Припускаючи, що "не вдаватися до програми" означає "використовувати лише ті програми, які доступні", звичайно.


Я перевірив це. Це набагато повільніше, ніж інші рішення, але працює.
aarona

Так, це досить довга труба для чогось такого простого. Я сподівався на ще кілька прапорів od, але не міг змусити це зробити те, що я хотів. Відповідь fmark, хоча і обробляє більше байтів, насправді може бути швидшою.
Томас

1
Це було б швидше, якби він використовував / dev / urandom, а не / dev / random
fmark

fmark має рацію, це може бути / dev / random тут, оскільки / dev / random - це справді генератор випадкових чисел і блокуватиме, коли більше не буде ентропії :)
LukeN

Це рішення, безумовно, є найбільш портативним! Він працює навіть на останньому Android (за винятком того, що його слід замінити -w16на -N16).
user1643723

1

Сподіваюся додати (можливо) краще рішення до цієї теми.

Зверніть увагу: це працює лише з 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 .

Тест:

З 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

1

Якщо ви використовуєте Linux, то Python буде попередньо встановлений. Тож ви можете піти на щось подібне до наведеного нижче:

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

Якщо вам не подобаються тире, використовуйте функцію заміни, як показано нижче

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

0

Ще одне, що ви можете додати, це запуск команди date наступним чином:

date +%S%N

Зчитує носекундний час, і результат додає багато випадковості.


0

Якщо у вас є opensslу вашій системі, ви можете використовувати її для генерації випадкових шістнадцяткових (також це може бути -base64) рядків із визначеною довжиною. Я знайшов це досить простим та придатним для використання в cron в однорядкових роботах.

 openssl rand -hex 32
 8c5a7515837d7f0b19e7e6fa4c448400e70ffec88ecd811a3dce3272947cb452
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.