MacOS X で Raspberry Pi 用の起動イメージファイルをSDカードに書き込む際の一連の作業を自動化するスクリプト
MacOS X で Raspberry Pi 用の起動イメージファイルをSDカードに書き込む際には、デバイスを umountdisk したり、dd したりするわけですが、この手の作業はデバイス名を間違えるといろんな意味でアウトですよね。
なので、この手の一連の作業を自動化するスクリプトを書いてみました。このスクリプトでは以下の流れを自動化しています。
- 作業開始前(SDカード装着前)のデバイス一覧を取得する
- SDカード装着後のデバイス一覧を取得して作業前の状態との差分を取り、対象のデバイス名を検出する。
- diskutil umountdisk を実行して書き込み準備する。
- デバイス名を rdisk に置換したデバイスに対して dd で書き込みする。pv がインストール済みの場合は進捗表示のために pv 経由で書き込む。
- 書き込み完了後に diskutil eject を行い、SD カードを抜いてよい状態にする。
こちらは実行例。
$ ./write_img2sd.sh OSMC_TGT_rbp2_20150519.img SDカードを装着して enter を押してください SDデバイス名を検出しました: /dev/disk2 SDカードへの書き込み準備を行います。プロンプトが表示された場合はログインパスワードを入力してください。 Password: Unmount of all volumes on disk2 was successful 256MiB 0:00:53 [4.81MiB/s] [=======================================================================>] 100% 0+4096 records in 0+4096 records out 268435456 bytes transferred in 53.217872 secs (5044085 bytes/sec) 書き込み完了しました Disk /dev/disk2 ejected SDカードデバイス /dev/disk2 を取り外してください。
スクリプト本体はこちらです。ただし、このスクリプトは sudo をする処理があります。内容の妥当性を適切に評価判断した上でご利用ください。
#!/bin/bash # # write_img2sd.sh if [ $(uname) != "Darwin" ]; then echo "このスクリプトは MacOS 専用です。処理を終了します。" exit 1 fi # 終了時に一時ファイルを消すための仕込み trap do_exit 0 1 2 3 13 15 ######################################## # 主処理部 do_main() { targetfile=$1 # 書き込み対象のファイルが存在することを確認する file_existcheck "$targetfile" # 作業開始時点(SDカード装着前)のドライブ一覧を取得する get_drivelist_prev echo "本スクリプトの実行前にSDカードを装着していた場合は、カードを抜いてからスクリプトを再実行してください。" echo -n "SDカードを装着して enter を押してください" read # SDカード装着後のドライブ一覧を取得する get_drivelist_post # SDカードのドライブを検出する detect_SD_device # SDカードのデバイス名を取得する sd_device=$( get_SD_devicename ) echo "SDデバイス名を検出しました: $sd_device" echo "" # SD カードへのディスクイメージ書き込みを行う write_image $targetfile $sd_device # デバイスを取り外し可能な状態にする detach_device $sd_device } ######################################## # ファイルの有無をチェックする file_existcheck() { if [ "$1" == "" ] || [ ! -e $1 ]; then echo "ファイル $1 が見つかりません。処理を終了します。" exit 1 fi } ######################################## # 作業開始前のドライブ一覧を取得する get_drivelist_prev() { file_diskutil_info_prev=$( mktemp ) diskutil list | awk '$1 ~ /^\// { print $1 }' > $file_diskutil_info_prev } ######################################## # 作業開始中のドライブ一覧を取得する get_drivelist_post() { file_diskutil_info_post=$( mktemp ) diskutil list | awk '$1 ~ /^\// { print $1 }' > $file_diskutil_info_post } detect_SD_device() { diff $file_diskutil_info_prev $file_diskutil_info_post > /dev/null if [ $? -eq 0 ]; then echo "SDカードを認識できません。カードを所定の手順で抜いた後、最初からやり直してください。" exit 1 fi } get_SD_devicename() { sort $file_diskutil_info_prev $file_diskutil_info_post | uniq -u rm $file_diskutil_info_prev $file_diskutil_info_post } write_image() { which pv > /dev/null if [ $? -eq 0 ]; then pvcat="pv" else pvcat="cat" fi rdevice=$( echo $2 | sed s#/dev/disk#/dev/rdisk#g ) echo "SDカードへの書き込み準備を行います。プロンプトが表示された場合はログインパスワードを入力してください。" #echo "sudo diskutil umountdisk $rdevice" sudo diskutil umountdisk $rdevice echo "$pvcat $1 | sudo dd of=$rdevice bs=1m" $pvcat $1 | sudo dd of=$rdevice bs=1m sync;sync;sync echo "書き込み完了しました" echo "" } detach_device() { diskutil eject $1 echo "SDカードデバイス $1 を取り外してください。" } do_exit() { for file in $file_diskutil_info_prev $file_diskutil_info_post ; do if [ -e $file ]; then rm $file fi done } do_main "$@"