web-dev-qa-db-ja.com

Kindlee-inkのヘルプ-ランダムな画像ファイルを表示する

私はこれに完全に慣れていませんが、他の誰かのコードを、壊れたKindle 3(電子書籍リーダー)の刑務所に適合させようとしています。

次のコードを使用して、0からXまでのランダムな(ish)数(Xは私が持っている画像の数、現在33)を生成して、ランダムな画像を何時間も(現在は2時間ごとに)表示できるようにしています。 ) cron を使用してスクリプトを実行します。

#generate random number between my 33 images (compatible with busybox)
n=32
while [ $n -ge 32 ]; do
n=1$(</dev/urandom tr -dc 0-9 | dd bs=5 count=1 2>/dev/null)
n=$((n-100000))
done
ImageNumber=$n

#My images are numbered as follows - pic_0.png, pic_1.png, pic_3.png... etc
SelectedImage=$( find /mnt/us/timelit/images/pic_${ImageNumber}*.png)

# clear the screen
eips -c

# show that image
eips -g $SelectedImage

それは機能していますが、解決する必要のあることがいくつかあります。

1)乱数が生成される前に時間とともに変化するため、スクリプトの乱数ジェネレーター部分に問題があると思います(以下のログを参照)

14:00:02: Script started
14:02:43: Random number is 2 
14:02:44: Image shown is pic_2.png 
15:00:02: Script started
15:00:19: Random number is 18 
15:00:20: Image shown is pic_18.png 
16:00:01: Script started
16:02:44: Random number is 10 
16:02:45: Image shown is pic_10.png  

2)時々、Kindleは画像の1つではなく空白の画面を表示します。生成された乱数に問題があると推測しています。つまり、一致する番号のPNGが見つからないため、Kindleの表示が空白になっています。

どんな助けでも大歓迎です。

3
user395294
#generate random number between my 33 images (compatible with busybox)
n=32
while [ $n -ge 32 ]; do
n=1$(</dev/urandom tr -dc 0-9 | dd bs=5 count=1 2>/dev/null)
n=$((n-100000))
done
ImageNumber=$n

したがって、ここでは乱数00000-99999を生成し、それが32未満の場合にのみ終了します。確率は100,000のうち32です。先頭の0が8進数として解釈されると、無効な算術式の問題が発生する可能性があります。 (編集:ああ、そういうわけであなたは1を前に付けます)

いずれにせよ、それは...終了するのにしばらく時間がかかります。そして、なぜ$RANDOM%32だけを使用しないのかという疑問が生じます。小さい数値の場合、$RANDOM(0-32767に制限されています)は正常に機能します。

Kindleのbusyboxに$RANDOMがない場合(CONFIG_ASH_RANDOM_SUPPORT=nの場合は可能)、tr...またはhexdumpが利用可能な場合は、1つの番号を取得できます。それを直接使用してください。

いずれにせよ、whileループは非常に非効率的で無意味です。

ループのない例:

random=1$(</dev/urandom tr -dc 0-9 | dd bs=5 count=1 2>/dev/null)
ImageNumber=$(($random % 32))

trは必要な5バイトよりもはるかに多くのランダムバイトを読み取らなければならないため、まだ少し非効率的です(256回の確率で10回の数字の読み取り)。

利用可能な場合はhexdumpを使用(固定の3ランダムバイトを読み取る):

 random=0x$(hexdump -v -e '3/1 "%02x"' -n 3 /dev/urandom)
 ImageNumber=$(($random % 32))
#My images are numbered as follows - pic_0.png, pic_1.png, pic_3.png... etc
SelectedImage=$( find /mnt/us/timelit/images/pic_${ImageNumber}*.png)

ImageNumberが1の場合、その式はpic_1*.pngに変換されます。これは、pic_1.pngだけでなく、pic_10-19.pngpic-100-199.pngなどにもなります。ファイル名に余分な文字がない場合は、*を削除します。それ以外の場合は、pic_${ImageNumber}_*.pngのような別の区切り文字が必要です(pic_1_spaceship.pngのようなファイル名を許可するため)。

どちらの方法でも、検索をスキップして、式を直接使用できます。

eips -g /mnt/us/timelit/images/pic_${ImageNumber}.png
1
frostschutz

コードがうまく機能しない理由については、 frostschutzの回答 を参照してください。私はさまざまな解決策を与えるつもりです。

BusyBox環境にawkが含まれている場合、このアプリケーションに十分な乱数を生成する簡単な方法は次のとおりです。

_awk -v n=32 'BEGIN {srand(); print int(Rand() * n); exit}'
_

srand()は、最も近い秒に丸められた現在の時刻のみに基づいているため、適切でない場合が多くあります(セキュリティ関連の場合、1秒に複数のランダムな描画がある場合)。 。しかし、ここではそれで十分です。

各画像に番号を割り当てて番号の範囲をハードコーディングするのではなく、ファイルを一覧表示してランダムに1つ選択します。より正確に:

  • 位置引数をファイルのリストに設定します。
  • Awkを使用して、1つの位置引数をランダムに選択します。
  • 位置引数からそのファイル名を選択します。
_set -- /mnt/us/timelit/images/pic*.png
i=$(awk -v n=$# 'BEGIN {srand(); print int(Rand() * n ) + 1; exit}')
eval "SelectedImage=\${$i}"

eips -c
eips -g $SelectedImage
_

Awkに画像ファイルを直接選択させることもできますが、ファイルがたくさんある場合は、コマンドラインの長さの制限に遭遇する可能性があります。

_SelectedImage=$(awk '
    BEGIN {srand(); print ARGV[int(Rand() * (length(ARGV)-1) + 1)]; exit}
  ' /mnt/us/timelit/images/pic*.png)
_

(bashとGNUユーティリティを備えたより完全な環境があれば、いくつかのことを行うためのより簡単な方法があることに注意してください。私の答えは、すべてのPOSIXシェルとで利用可能な機能に固執します。多くのBusyBoxインストール。)