web-dev-qa-db-ja.com

UNIXシェルでランダムなファイル名を生成する

UNIXシェル(tcshellなど)でランダムなファイル名を生成したいと思います。ファイル名は、ランダムな32桁の16進文字で構成する必要があります。例:

c7fdfc8f409c548a10a0a89a791417c5

(必要なものはすべて追加します)。ポイントは、プログラムに頼らずにシェルでのみできることです。

69
R S

Linuxを使用している場合、次のように動作します。

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

これは、システムのエントロピーが低い場合にのみ擬似ランダムですが、(Linuxでは)終了することが保証されています。本当にランダムなデータが必要な場合は、/dev/randomの代わりにcat /dev/urandomを使用します。この変更により、真にランダムな出力を生成するのに十分なエントロピーが利用可能になるまでコードがブロックされるため、コードの速度が低下する可能性があります。ほとんどの場合、/dev/urandomの出力は十分にランダムです。

OS Xまたは別のBSDを使用している場合は、次のように変更する必要があります。

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

unix mktempコマンドを使用しない理由:

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

1つのコマンド、パイプ、ループなし:

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

改行が必要ない場合、たとえば変数で使用する場合:

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

「16」を使用すると、32桁の16進数が生成されます。

19

おそらくそれぞれの答えからお気づきのように、一般的にhaveを「プログラムに再分類」します。

ただし、外部実行可能ファイルを使用せずに、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に変更して、アルファベットの16進文字を大文字にします。

Bashでそれを行う別の方法を次に示しますが、明示的なループはありません。

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

以下では、「最初」と「2番目」printfは、行に表示される順序ではなく、実行される順序を指します。

この手法では、ブレース展開を使用して、16を法とする32個の乱数のリストを作成し、それぞれにスペースと、中かっこで囲まれた範囲内の数字の1つと別のスペースが続きます(例:11 00)。そのリストの各要素について、最初のprintfは、フォーマット文字列(%.2)を使用して最初の2文字を除くすべてを取り除きます。フォーマット文字列のスペースにより、各出力番号の間に少なくとも1つのスペースが確保されます。

最初のprintfを含むコマンド置換は引用符で囲まれないため、Word分割が実行され、各数値は個別の引数として2番目のprintfに送られます。そこで、数値は%Xフォーマット文字列によって16進数に変換され、スペースなしで相互に追加され(フォーマット文字列にはないため)、結果はstringという名前の変数に格納されます。

printfがそのフォーマット文字列のアカウントより多くの引数を受け取ると、すべての引数が消費されるまで、フォーマットが各引数に順番に適用されます。引数が少ない場合、一致しない書式文字列(部分)は無視されますが、この場合は適用されません。

Bash 3.2、4.4、5.0-alphaでテストしました。ただし、RANDOMはこれらのシェルのブレース展開で1回しか評価されないため、zsh(5.2)またはksh(93u +)では機能しません。

0から32767の範囲の値でmod演算子を使用するため、スニペットを使用した数字の分布が歪む可能性があることに注意してください(数値がpseudoそもそもランダム)。ただし、mod 16を使用しているため、32768は16で割り切れるので、ここでは問題になりません。

いずれにせよ、これを行う正しい方法は、Oleg Razgulyaev's answerのようにmktempを使用することです。

6

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
5
LukeN

さらに別の方法[tm]。

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

この回答はfmarksに非常に似ているため、実際に信用することはできませんが、catコマンドとtrコマンドの組み合わせは非常に遅く、このバージョンはかなり高速であることがわかりました。 hexdumpが必要です。

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

最初の答えは良いのですが、なぜ猫を必要としないならフォークするのですか。

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

Linuxを使用している場合は、Pythonが事前にインストールされています。したがって、次のようなものを探すことができます。

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

ダッシュが気に入らない場合は、次に示すように置換機能を使用します

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

/dev/randomから16バイトを取得し、16進数に変換し、最初の行を取得し、アドレスを削除し、スペースを削除します。

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

もちろん、「プログラムに頼らずに」とは、「すぐに利用可能なプログラムのみを使用する」ことを意味します。

1
Thomas

このトピックに(おそらく)より良いソリューションを追加したいと考えています。

注意:これはbash4およびmktempの実装(たとえば、GNU one)でのみ動作します

これを試して

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

これはhead /dev/urandom | tr -cd 'a-f0-9' | head -c 32の2倍、cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32の8倍高速です。

基準:

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
罗泽轩

uuidgenは、これを正確に生成しますが、ハイフンを削除する必要があります。だから、これがこれを達成する最もエレガントな(少なくとも私にとって)方法であることがわかりました。 LinuxおよびOS Xでそのまま使用できるはずです。

uuidgen | tr -d '-'
0
danran

追加できるもう1つのことは、次のようにdateコマンドを実行することです。

date +%S%N

数秒の時間を読み取り、結果は多くのランダム性を追加します。

0
user3174711

システムにopensslがある場合は、それを使用してランダムな16進数を生成できます(-base64)定義された長さの文字列。私は非常にシンプルで、cronで1行のジョブで使用できることに気付きました。

 openssl Rand -hex 32
 8c5a7515837d7f0b19e7e6fa4c448400e70ffec88ecd811a3dce3272947cb452
0
Alex