LoginSignup
13
12

More than 3 years have passed since last update.

シェルスクリプトで自動インストールスクリプトを作成する際の注意点メモ

Last updated at Posted at 2020-12-04

よくミスるのでメモです。

手動手順を自動実行するスクリプトのエラーを確実に検出する点で、ソフトウェアテストの小ネタの仲間に入れて下さい。。。(思想的には共通部分があるはず、、)

ホスト環境に開発環境構築する場合などを想定

sudo apt-get update時にパスワードを聞かれないようにする(参考)

sudoersを更新することで可能

$ sudo visudo    # 以下の行に追加する
# Allow members of group sudo to execute any command
%sudo  ALL=(ALL:ALL) NOPASSWD:ALL

上記だと、セキュリティ的に良くないことも多いと思うので、usernameを指定する場合は以下

username ALL=NOPASSWD: ALL

もしくは、sudo -Sでパスワードをパイプで受け取る

echo 'passwd' | sudo -S apt-get update

対話処理は先に実行しておく

例えばOpenCVビルド時は対話処理が必要なので先に実行しておく

sudo apt-get update -y
sudo apt-get install -y gdm3  ## 対話ウィンドウが出たら --> OK --> gdm3 を選択
cd ~
git clone https://github.com/mdegans/nano_build_opencv
cd nano_build_opencv
./build_opencv.sh 3.4.10

yes/noが聞かれる場合にy/nを自動入力

yesnoコマンドを使う

yes | ./build_opencv.sh 3.4.10

yesはずっとyを出力する

$ yes
y
y
y
...

エラー発生時はエラー終了させる

1部だけエラーになっても素通りすると後から分かりづらいので、エラー側に倒す

trapset -Eを使うと便利

# エラーが起こったら異常終了させる
set -E

function failure(){
    echo "error end!!"
    exit 1
}

# エラー発生時にコールする関数を設定 
trap failure ERR

|を使ってパイプで結果を渡す途中のエラーも検知する場合は、set -eo pipefailを設定すると便利

#!/bin/bash
set -eo pipefail

sl | ls
echo "don't show this comment"

部分的にエラー処理したい場合は、$?で結果を判断しても良いかもしれないです。

ls test.txt
RESULT=$?   # no such file or firectoryのとき1がはいる
if [ $RESULT -ne 0 ];then
    echo "no file"
fi

エラー関数がある場合は、||で結果を渡しても良いかもしれないです。

function func_error(){
    echo "error"
}
ls test.txt || func_error # no such file or firectoryのときfunc_errorが実行される

前処理でrm -rする場合はエラーにならないようにする

rm -rfだと、指定したdirectoryがない時にエラーにならない

$ sudo rm -rf directory_name
$ echo $?
0

rm -rだと、指定したdirectoryがない時にエラーになる

$ sudo rm -r directory_name
rm: directory_name: No such file or directory
$ echo $?
1

$HOME/.bashrcにリダイレクトする場合

$HOME/.bashrc読み込み時に実行したいコマンドがある場合は'シングルクオーテーション'で囲む

echo 'eval `dbus-launch --sh-syntax`' >> $HOME/.bashrc

逆に、$HOME/.bashrcへのリダイレクト時に実行したいコマンドがある場合は"ダブルクオーテーション"で囲む

echo "echo `date`" >> $HOME/.bashrc

'シングルクオーテーション'の場合は文字列のまま、"ダブルクオーテーション"の場合はコマンドが実行された結果が展開される。

$ echo 'echo `date`'
echo `date`
$ echo "echo `date`" 
echo 2020年 11月21日 土曜日 23時22分15秒 JST

ライブラリバージョンチェック

厳密にライブラリバージョンの一致が必要な場合は、チェックをしても良さそう。

# ex. opencv pythonのバージョンを調べる場合
python3 -c "import cv2 ;print(cv2.__version__);"

複数回実行時にエラーにしない

インストール手順アップデートなどにより、、同じスクリプトを複数回実行する場合がある。
この場合に異常側になるべく倒さない方が便利な時もある。
例えば、既にrosをインストールしている場合はスキップ側に倒すなどした方がいい時もある。。

function install_ros(){
    # check if already install ros
    rosversion -d
    ret=$?
    if [ $ret -eq 0 ];then
       echo "ros already installed, skip install ros"
       return 0
    fi

    # install ros
    # ...
}

ただし-e指定してる場合はエラーになるので、この場合はifの中に含むとよい

#!/bin/bash

set -e

if [ ! -z `env | grep "ROS_DISTRO"` ];then
    echo "ROS_DISTRO found"
else
    echo "ROS_DISTRO not found"
fi

環境変数よりコマンド実行結果をみた方が良い場合もある

#!/bin/bash

set -e

if [ ! -z `rosversion -d` ];then
    echo "ROS_DISTRO found"
else
    echo "ROS_DISTRO not found"
fi

周辺パッケージアップデートの影響をなるべく回避する

開発が活発なライブラリを使う場合は、アップデート時のデグレを引くこともある。
branch指定、もしくは動作確認時点のバージョン指定により回避する。

git clone http://github.com/test/repository
git checkout xxx  # branch指定、もしくは動作確認時点のバージョン指定

機械学習ライブラリ系は、特に変化が大きいのでバージョン固定する方がよさそうです。
但し、周辺パッケージの変化に気付き難くなるので一概に解決とは言えない。。

その他

何かより良い方法がありましたらアドバイス頂けると幸いです。

参考

sudo のパスワードを入力なしで使うには
シェルスクリプトでset -eしているときに処理を中断せずエラーを扱う方法

13
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
12