it-swarm.com.de

Generieren Sie einen zufälligen Dateinamen in der Unix-Shell

Ich möchte in der Unix-Shell einen zufälligen Dateinamen generieren (zB tcshell). Der Dateiname sollte aus 32 zufälligen Buchstaben bestehen, z. B .:

c7fdfc8f409c548a10a0a89a791417c5

(dazu werde ich hinzufügen, was immer nötig ist). Es geht darum, dies nur in Shell zu tun, ohne auf ein Programm zurückgreifen zu müssen.

66
R S

Vorausgesetzt, Sie sind auf einem Linux, sollte Folgendes funktionieren:

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

Dies ist nur pseudo-zufällig, wenn Ihr System an Entropie leidet, aber (unter Linux) garantiert terminiert wird. Wenn Sie wirklich zufällige Daten benötigen, können Sie /dev/random anstelle von /dev/urandom verwenden. Durch diese Änderung wird Ihr Code so lange blockiert, bis ausreichend Entropie verfügbar ist, um eine wirklich zufällige Ausgabe zu erzeugen. Dies kann Ihren Code verlangsamen. Für die meisten Zwecke ist die Ausgabe von /dev/urandom ausreichend zufällig.

Wenn Sie unter OS X oder einer anderen BSD arbeiten, müssen Sie Folgendes ändern:

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

warum nicht den Unix-Befehl mktemp verwenden:

$ TMPFILE=`mktemp tmp.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` &&  echo $TMPFILE
tmp.MnxEsPDsNUjrzDIiPhnWZKmlAXAO8983
40
Oleg Razgulyaev

Ein Befehl, keine Pipe, keine Schleife:

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

Wenn Sie den Zeilenumbruch nicht benötigen, wenn Sie ihn beispielsweise in einer Variablen verwenden:

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

Bei Verwendung von "16" werden 32 Hexadezimalstellen generiert.

17

Wie Sie wahrscheinlich aus jeder der Antworten ersehen haben, müssen Sie im Allgemeinen auf "ein Programm zurückgreifen".

Ohne die Verwendung von externen ausführbaren Dateien in Bash und ksh:

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

in zsh:

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

Ändern Sie den Kleinbuchstaben xin der Formatzeichenfolge in einen Großbuchstaben Xname__, damit die alphabetischen Hexadezimalzeichen in Großbuchstaben umgewandelt werden.

Hier ist eine andere Möglichkeit, dies in Bash zu tun, jedoch ohne explizite Schleife:

printf -v string '%X' $(printf '%.2s ' $((RANDOM%16))' '{00..31})

Im Folgenden beziehen sich "first" und "second" printfauf die Reihenfolge, in der sie ausgeführt werden, und nicht auf die Reihenfolge, in der sie in der Zeile erscheinen.

Diese Technik verwendet die Klammererweiterung, um eine Liste von 32 Zufallszahlen Mod 16 zu erzeugen, gefolgt von einem Leerzeichen und einer der Zahlen im Bereich in Klammern, gefolgt von einem anderen Leerzeichen (z. B. 11 00). Für jedes Element dieser Liste entfernt der erste printfalle bis auf die ersten beiden Zeichen mithilfe seiner Formatzeichenfolge (%.2), wobei entweder einzelne Ziffern, gefolgt von einem Leerzeichen, oder zwei Ziffern verbleiben. Das Leerzeichen in der Formatzeichenfolge stellt sicher, dass zwischen jeder Ausgabenummer mindestens ein Leerzeichen steht.

Die Befehlsersetzung, die den ersten printfenthält, wird nicht in Anführungszeichen gesetzt, sodass die Wortteilung durchgeführt wird und jede Zahl als separates Argument an den zweiten printfübergeben wird. Dort werden die Zahlen durch die Formatzeichenfolge %X in hexadezimal umgewandelt und ohne Leerzeichen aneinander angehängt (da keine in der Formatzeichenfolge enthalten sind). Das Ergebnis wird in der Variablen stringgespeichert.

Wenn printfmehr Argumente empfängt, als die Formatzeichenfolge berücksichtigt, wird das Format nacheinander auf jedes Argument angewendet, bis alle verbraucht sind. Wenn weniger Argumente vorhanden sind, wird die nicht übereinstimmende Formatzeichenfolge (Teil) ignoriert, dies gilt jedoch in diesem Fall nicht.

Ich habe es in Bash 3.2, 4.4 und 5.0-alpha getestet. In zsh (5.2) oder ksh (93u +) funktioniert dies jedoch nicht, da RANDOMin der Klammererweiterung in diesen Shells nur einmal ausgewertet wird.

Beachten Sie, dass aufgrund der Verwendung des Mod-Operators für einen Wert im Bereich von 0 bis 32767 die Verteilung der Ziffern mithilfe der Ausschnitte verzerrt werden kann (ganz zu schweigen von der Tatsache, dass die Zahlen Pseudo sind. zufällig in erster Linie). Da wir jedoch Mod 16 verwenden und 32768 durch 16 teilbar ist, ist dies hier kein Problem.

In jedem Fall ist es richtig, mktempwie in Oleg Razgulyaevs answer zu verwenden.

6

In zsh getestet, sollte mit jeder BASH-kompatiblen Shell funktionieren!

#!/bin/zsh

SUM=`md5sum <<EOF
$RANDOM
EOF`

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

echo "Your new filename: $FN"

Beispiel:

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

Noch ein anderer Weg.

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

Diese Antwort ist fmarks sehr ähnlich, daher kann ich es nicht wirklich würdigen, aber ich fand die Befehlskombinationen von cat und tr ziemlich langsam und diese Version war etwas schneller. Du brauchst einen Hexdump.

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

Die erste Antwort ist gut, aber warum ist Fork Cat nicht erforderlich. 

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

Wenn Sie Linux verwenden, wird Python bereits vorinstalliert. So können Sie etwas Ähnliches wie das Folgende suchen:

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

Wenn Sie die Striche nicht mögen, verwenden Sie die Ersetzen-Funktion (siehe unten)

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

Holen Sie sich 16 Bytes von /dev/random, konvertieren Sie sie in Hex, nehmen Sie die erste Zeile, entfernen Sie die Adresse, entfernen Sie die Leerzeichen.

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

Angenommen, "ohne auf ein Programm zurückzugreifen", bedeutet natürlich "nur Programme verwenden, die ohne weiteres verfügbar sind".

1
Thomas

Ich hoffe, ich kann diesem Thema eine (vielleicht) bessere Lösung hinzufügen.

Hinweis: Dies funktioniert nur mit bash4 und einigen Implementierungen von mktemp (zum Beispiel dem GNU)

Versuche dies

fn=$(mktemp -u -t 'XXXXXX')
echo ${fn/\/tmp\//}

Dieser ist doppelt so schnell wie head /dev/urandom | tr -cd 'a-f0-9' | head -c 32 und achtmal so schnell wie cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32.

Benchmark:

Mit 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

Und der andere:

#!/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
罗泽轩

uuidgen generiert genau dies, außer Sie müssen Bindestriche entfernen. Ich fand das die eleganteste (zumindest für mich) Möglichkeit, dies zu erreichen. Es sollte sofort unter Linux und OS X funktionieren.

uuidgen | tr -d '-'
0
danran

Sie können das Datum auch wie folgt hinzufügen:

date +%S%N

Liest nicht-Sekunden-Zeit und das Ergebnis fügt viel Zufall hinzu.

0
user3174711

Wenn Sie openssl in Ihrem System haben, können Sie damit zufällige Hex-Strings (auch -base64) mit definierter Länge erzeugen. Ich fand es ziemlich einfach und brauchbar in cron in einer Zeile.

 openssl Rand -hex 32
 8c5a7515837d7f0b19e7e6fa4c448400e70ffec88ecd811a3dce3272947cb452
0
Alex