bashの基礎
参考書籍 : 実践bashによるサイバーセキュリティ対策
・出力
echoコマンドで出力を行うことができる
$ echo "Hello World" Hello World
組み込みコマンドのprintfで整形出力ができる
$ printf "Hello World\n\n"
・変数
bash変数の命名規則 : 先頭がアルファベットか_で後続が英数字
別途定義がなければ、変数は文字列変数となる
変数の頭に$をつけて変数の値を取得できる
$ MYVAR=textforavalue # =の前後にスペースを入れないこと $ echo $MYVAR # MYVARの中身は文字列 textforavalue
"を使うことで、文字列内の変数の置換ができる
$ firstvar=beginning $ secondvar="this is just the $firstvar" $ echo $secondvar this is just the beginning
$( )構文を用いて、コマンドの出力を変数に格納できる
CMDOUT=$(pwd)
・位置パラメータ
bashスクリプト内で、パラメータを取得できる。
渡された最初のパラメータは$1, 次のパラメータはs2, 次はs3... というように特殊な変数に格納される
$0はスクリプト名を表す特別なパラメータで、$#はパラメータ数を表す変数として予約されている
↓のようなechoparams.shを作成する
#!/bin/bash - echo $# echo $0 echo $1 echo $2 echo $3
実行すると、パラメータが表示される
$ ./echoparams.sh bash is fun 3 ./echoparams.sh bash is fun
・入力
readコマンドで、ユーザーからの入力を標準入力から受け取ることができる
$ read MYVAR $ echo "$MYVAR"
・条件
bashから起動するコマンドやプログラムは、成功もしくは失敗を示す値を常に返す
この値は、コマンド実行直後に変数$?で参照できる。0が返却されたら成功もしくは真、それ以外の値は失敗もしくは偽とみなされる
if cd /tmp then # 成功時 echo "here is what is in /tmp:" ls -l fi
パイプで結合されたコマンドも扱うことができる。結合されたコマンドの、最後に実行されるコマンドの返却値で条件分岐する
if ls | grep pdf then # 真 echo "found one or more pdf files here" else # 偽 echo "no pdf files found" fi
"最後に実行されるコマンドの返却値で条件分岐する"点に注意
次のコマンドの場合、wc(単語数をカウントする)はpdfファイルが0でも、カウントには成功し真になる
$ ls | grep pdf | wc
if文は、組み込みコマンド[やtest、[[と組み合わせて使われる
[とtestは同じコマンドだが、[[は少し動作が異なる。基本的には[[を使うべきである。↓が詳しい
test と [ と [[ コマンドの違い - 拡張 POSIX シェルスクリプト Advent Calendar 2013 - ダメ出し Blog
ファイルがファイルシステム上に存在するかの例を示す
if [[ -e $FILENAME ]] then echo $FILENAME exists fi
if文により可能なファイル評価の一覧を示す
-d : ディレクトリかどうかを評価する
-e : ファイルかどうかを評価する
-r : ファイルが存在しており、かつ読み取り可能かを評価する
-w : ファイルが存在しており、かつ書き込み可能かを評価する
-x : ファイルが存在しており、かつ実行可能かを評価する
変数の値の比較の例を示す
if [[ $VAL -lt $MIN ]] then echo "value is too small" fi
if文により実行可能な数値評価の一覧を示す
-eq : 数値が等しいかを評価する
-gt : ある数値(左)が別の数値(右)より大きいかを評価する
-lt : ある数値(左)が別の数値(右)より小さいかを評価する
<を用いて数値評価を行いたいときは、((で囲む
((内では、変数の値を参照するときに$は不要だが、$1, $2, $#, $?などの特別な変数は$を付けて参照すること
if (( VAL < 12 )) then echo "value $VAL is too small" fi
※((内では、0以外の値が真となることに注意する。そのため、コマンドの実行結果を((内に含めないほうがわかりやすい
if/then構文以外にも、条件分岐を行うことが可能
コマンドを&&や||で区切って実行できる。
cd $DIR && ls と実行した場合、前のコマンド成功時に後のコマンドが実行される
cd $DIR || echo cd failed と実行した場合、前のコマンド失敗時に後のコマンドが実行される
この構文は、コマンドだけでなく[[の評価も利用できる。
[[ -d $DIR ]] && ls "$DIR"
というコマンドも実行できる
また、;を使い、一行で複数のコマンドの実行ができる。cd $DIR ; ls のように実行できる。
・ループ
while構文でループ処理が可能
真偽値には、コマンドもしくは{や((を利用できる
do, doneで処理のグルーピングを行う
i=0 while (( i < 1000 )) do echo $i let i++ done
letコマンドでインクリメントを実行させ、iが1000未満の間繰り返している。
条件式にコマンドを使う場合は以下のようになる
# pdfファイルが無いディレクトリまで遡る while ls | grep -q pdf do echo -n "there is a file with pdf in its name here :" pwd cd .. done
forループもbashで使用できる
単純な数値のループは((を使用する
for (( i=0; i < 100; i++ )) do echo $i done
シェルスクリプトのパラメータを順に利用するには、任意の名前の変数を利用する
for ARG do echo here is an argument: $ARG done
このスクリプトの動作は次のようになる
$ ./xxx.sh bash is fun here is an argument: bash here is an argument: is here is an argument: fun
3つめのforの利用方法は、任意の値のリストを利用する方法である。
for VAL in 20 3 dog peach 7 vanilla do echo $VAL done
値のリストは、コマンドの結果や{..}で生成できる
for VAL in $(ls | grep pdf) {0..5} do echo $VAL done
・関数
次のような構文で関数を定義できる
function myfunc () { # 関数の処理 echo "Hello, world!" } # 関数呼び出し myfunc
関数呼び出しは、関数名のみ記述する。
関数の引数は、関数内で$1, $2...で参照できる
function myfunc () { echo $1 echo $2 } myfunc Hello World
関数の戻り値は、成功した場合0、エラーが発生したら0以外となる。
値を返却したい場合は、グローバル変数を利用して受け渡しを行う
rtn="" function myfunc () { rtn=$(pwd) } myfunc echo $? echo $rtn
・bashにおけるパターンマッチング
アスタリスク(*)は任意の文字数の任意の文字にマッチする
?は単一の文字にマッチする
構文では、内のいずれか一つとマッチする。[^]で[^]内のいずれか以外の一つとマッチする。
[]内にクラスを指定できる。例えば、[:alnum:]など
例えば、
$ ls | grep *[[:punct:]]jpg
はtest.jpgにマッチする
アスタリスク(*)や?をパターンマッチングとして使用しない場合、\でエスケープする
""の内部ではパターンマッチングが行われない
・初めてのスクリプト--OSタイプの検出
OSに固有のコマンドを確認することで、OSタイプを検出するスクリプトの例を示す。
#!/bin/bash - if type -t wevtutil &> /dev/null # wevtutilコマンドの存在を確認 then OS=MSWin elif type -t scutil &> /dev/null # scutilコマンドの存在を確認 then OS=macOS else OS=Linux fi echo $OS