はじめに
シェルスクリプトにまつわる記事を投稿し始めて、早くも3本目。これまでは実際に.shファイルを作成するまでの基礎的な部分を説明してきたため、実際にファイルを作って動かしてみることはやってきませんでした。
しかし改めて.shファイルを記述して、エラーを出して、なんとか動かしてみるとやっぱりこれが一番楽しいですね。エンジニアになって良かった。地球に生まれて良かったとすら思えます。
前回までの記事:
具体的に行った手順をメモにして残して、読んでいただけた方には実際に手を動かしてシェルスクリプトを書いて欲しいですね。それが上達にもつながる気がしています。
通して読んでくださっている方には本当に感謝です。それでは文法から、見ていきましょう!
シェルスクリプトの基本
シェルスクリプトは独特の文法構造を持っており、やはり書いていかないことには身につかないと思います。(変数の定義にスペースを使わない。全角スペースが入っていても空行は無視される。等)
基本的な文法を下記のようにまとめておくので、ぜひ手を動かして書いてみて欲しいです。
全て私が実践して、実際に動いたスクリプトを掲載しています。動かせる環境を作れることも重要なのでご自身でやってみてください。それでは行きましょう。
シェルスクリプトの行
・\で改行できる。(\はoption+¥キーで入力できる)
#!/bin/bash -eu
echo \ (変なところで改行している。)
"Today's dinner."
mbp:shellscripts kentaroyoshizumi$ . dinner.sh (カレントディレクトリでdinner.shを実行せよという意味)
Today's dinner.
コメント
**・#の直後はコメントになる。
#!/bin/bash -eu
echo \
"Today's dinner." #today is my birthday.
変数
シェルスクリプトで使用する変数を「シェル変数」と呼ぶ。シェル変数を定義するには、変数名の前に「$」をつける。
ただし注意もあり、
- 変数を定義する際に$をつけてしまうとエラーになる。
- 変数を定義する際に=の前後にスペースを入れてしまうとエラーになる。(birthday = 1021 等)
- 変数名に利用できるのはアルファベットと数字と_のみ。
- 変数名に_を使用する際には{}で括らなければならない。(後述)
#!/bin/bash -eu
bitrthday=1021
echo $birthday
実行結果
mbp:shellscripts kentaroyoshizumi$ . birthday.sh
1021
変数名に_を使用する際には{}で括らなければならない。
#!/bin/bash -eu
bitrthday=1021
echo $birthday_today_is_my_birthday
実行結果
mbp:shellscripts kentaroyoshizumi$ . birthday.sh
(何も表示されない)
#!/bin/bash -eu
bitrthday=1021
echo ${birthday}_todayismybirthday
実行結果
mbp:shellscripts kentaroyoshizumi$ . birthday.sh
1021_todayismybirthday
クォーティング
シングルクォートとダブルクォートで実行結果が異なる。
#!/bin/bash -eu
country=Japan
echo 'I came from $country'
echo "I came from $country"
実行結果
I came from $country
I came from Japan
コマンド置換
コマンドの結果を文字列として取得する。
#!/bin/bash -eu
filename=$(date '+%Y-%m-%d')
echo "$filename"
実行結果
2022-03-27
位置パラメータ
めっちゃ使います!
$ echo $?
0
直前に使用したコマンドがうまく行ったかどうかを示す。(0なら成功、1は失敗)
位置パラメータのテスト用シェルスクリプト
#!/bin/bash -eu
echo "\$0 = $0"
echo "\$1 = $1"
echo "\$2 = $2"
echo "\$3 = $3"
コマンドラインから以下を実行
$ ./param.sh aaa ggg ttt
出力結果
$0 = ./param.sh
$1 = aaa
$2 = ggg
$3 = ttt
制御構造
bashは他のプログラミング言語同様条件分岐や繰り返し処理を行うことができる。
if文
#!/bin/bash -eu
if [ "$1" = "bin" ]; then
echo "OK"
else
echo "NG"
fi
for文
単語のリストに対して繰り返し処理を行う
#!/bin/bash -eu
for name in aaa ccc ggg
do
echo $name
done
実行結果
aaa
ccc
ggg
case文
指定された文字列がパターンにマッチするか判定し、パターンごとに対応した処理を行う。
#!/bin/bash -eu
case "$1" in
*.txt)
less "$1"
;;
*.sh)
vim "$1"
;;
*)
echo "not supported file : $1"
;;
esac
実行結果
mbp:shellscripts kentaroyoshizumi$ . case-test.sh /Users/kentaroyoshizumi/Downloads/RubyProject
not supported file : /Users/kentaroyoshizumi/Downloads/RubyProject
while文
指定した条件が真である限りくりかえし処理を行う。
#!/bin/bash -eu
i=1
while [ "$i" -le 10 ]
do
echo "$i"
i=$((i + 2))
done
実行結果
mbp:shellscripts kentaroyoshizumi$ . while.sh
1
3
5
7
9
シェル関数
シェルスクリプト内で関数を定義する
#!/bin/bash -eu
horizonte ()
{
date
du -h ~| tail -n 1
}
horizonte
実行結果
mbp:shellscripts kentaroyoshizumi$ . func-test.sh
2022年 4月 2日 土曜日 16時58分49秒 JST
シェル関数内での位置パラメータ
シェルスクリプトの中で位置パラメータを使用する。
#!/bin/bash -eu
echo_parameter ()
{
echo "\$1 = $1"
echo "\$2 = $2"
echo "\$3 = $3"
echo
echo "$# arguments"
echo "scripts name= $0"
}
echo_parameter aaa bbb ccc
シェルスクリプトの活用
演習1-1 指定されたファイルやディレクトリの概要を表示するシェルスクリプト
#!/bin/bash -eu
file=$1
if [ -d "$file" ]; then
echo "$file is a directory:"
ls "$file"
elif [ -f "$file" ]; then
echo "$file is a regular file:"
head -n 5 "$file"
fi
実行結果
shellscripts is a directory:
birthday.sh date.sh if-bin.sh summarize.sh
daily.sh dinner.sh param.sh
演習1-2 前問の複数ファイルを指定したもの
#!/bin/bash -eu
for file in "$@"
do
if [ -d "$file" ]; then
echo "$file is a directory:"
ls "$file"
elif [ -f "$file" ]; then
echo "$file is a regular file:"
head -n 5 "$file"
fi
done
実行結果
RubyProject is a directory:
2:15_S3_or_not.drawio hello_ruby
2:15_S3_or_not.png mail
Yoshizumi_new.drawio monitoring_solution.png
Yoshizumi_solution13.drawio my-portfolio-site.drawio
Yoshizumi_solution13.png my-portfolio-site.png
Yoshizumi_solution14.png new.drawio
batch_sample ninjacode
business-idea.drawio rails-hotel-search-linebot
business_idea.drawio rails-lecture
business_idea.png rails-react-auth
docker-compose1.yml renew_datamonitoring.drawio
docker-practice renew_datamonitoring.png
hello.rb ruby-lecture
演習2 日記を書くスクリプト
①daily.shというファイルを作成して、vimで編集していく。
mbp:shellscripts kentaroyoshizumi$ touch daily.sh
mbp:shellscripts kentaroyoshizumi$ vim daily.sh
#!/bin/bash #(シバンを指定する。今回はやはりbash)
#日記データを保存するディレクトリ
directory="${HOME}/shellscripts"
#保存するディレクトリがなければ作る
if [ ! -d "$directory" ]; then
mkdir "$directory"
fi
vim "${directory}/$(date '+%Y-%m-%d').txt" #(shellscripsというディレクトリに日付.txtという名前で保存した後vimで編集する。)
演習3 指定したパスのファイル一覧
#!/bin/bash -eu
list_recursive ()
{
local filepath=$1
local indent=$2
echo "${indent}${filepath##*/}"
if [ -d "$filepath" ]; then
local fname
for fname in $(ls "$filepath")
do
list_recursive "${filepath}/$
{fname}" " $indent"
done
fi
}
list_recursive "$1" ""