シェルスクリプトやってみようよ


Linux、コマンド、シェル、、、、そういう類の食わず嫌いを克服しました!!
この記事では、私が参考にさせていただいたサイトを紹介しながら、疑問点や解釈を補足していきます。
この記事が、「やってみよかな」「黒い画面こわい」と思っている方の一助になれば幸いです。

シェルスクリプトって何?

これはいろいろなところで解説されていますが、私の解釈でひとことで言うとPCへの命令をひとまとめにしたプログラムです。

たとえば、ファイル名を変更したいとき。
複数あるファイル名の「試験」と「テスト」の文言の揺らぎを統一したいときに、ファイルやディレクトリを指定して一気にリネームする。とか。

もうひとつ例、実行したコマンドのログのファイルを毎日作成したい(ロギング、というらしい)。とか。
・・・まって、それはバッチ処理のことじゃないの??と思い、調べました。
→ https://wa3.i-3-i.info/word11221.html
どうやらシェルスクリプトとバッチファイルは役割は同じで、ベースの世界が違うだけらしい。

スクリプト作成方法と実行方法

macOSの方は環境構築等なしでターミナルから実行できますが、Windowsの方は準備が必要です。「Windows Linux」等でググってみてください

以下のスクリプト作成方法と実行方法を参考にしました↓
https://udemy.benesse.co.jp/development/web/shellscript.html

エディタはVi(ヴィーアイ)を利用していますが、テキストエディタならだいたいなんでもいけるはず。
最近は、Viの進化版であるVim(ヴィム)が人気らしい。
ViやVimは設定すればコードの色分けができますが、今回は割愛します。
VS Codeだと自動で色分けしてくれて見やすいです。優しい。

権限について

全てのファイルやフォルダには権限が付与されています。
誤ってシェルを実行してしまったり、本番環境のソースや設定ファイルを編集できないようにするなどの事故を防ぐために設定できます。
ls -lで権限が確認できます。

$ ls -l
total 13784
drwxr-xr-x  4 aaaaaayyymmm  staff     128  3 20 15:19 memo
drwxr-xr-x  7 aaaaaayyymmm  staff     224  3 29 23:52 tmp
-rw-------  1 aaaaaayyymmm  staff  124987  3 30 11:51 アーカイブ.zip
-rw-r--r--  1 aaaaaayyymmm  staff  197519  3 31 16:00 スクリーンショット.png
-rw-r--r--  1 aaaaaayyymmm  staff      17  3 31 16:55 hello.sh

それぞれの項目の意味は以下です。

ファイルタイプ 権限 ハードリンクの数 所有者 グループ バイトサイズ タイムスタンプ ファイル名
-(1文字目の部分) rw-r--r-- 1 aaaaaayyymmm staff 17 3 31 16:55 hello.sh

今回は、ファイルタイプ権限に注目します。
ファイルタイプには、以下の3種類があります。

タイプ 意味 補足
- ファイル ---
d ディレクトリ GUIで見るフォルダと同じモノ
l シンボリックリンク ショートカットみたいなモノ。本物のファイルやディレクトリを読み書きできるようになっている代理人的なファイル

権限の見方は、左から3つずつ区切って、所有者グループその他のユーザの権限を表しています。
そして、権限の種類は以下の通りです。

権限 数字表記 意味
r 4 読み取り
w 2 編集
x 1 実行
- なし 権限なし

権限付与の方法

主に2種類の書き方ができます。

数字指定ver.の例
$ chmod 744 hello.sh
アルファベット指定ver.の例
$ chmod g+wx hello.sh
//または
$ chmod u=x,g=rwx,o=- hello.sh

こちらの記事を参考にさせていただきました。さらに詳しく知りたい方は以下を参照ください。
https://qiita.com/shisama/items/5f4c4fa768642aad9e06

デフォルトでは-rw-r--r--になっています。
スクリプトを作成後に実行するには、以下のようにして実行権を与える必要があります。
(デフォルト権限は変更可能ですが、今回は扱いません。)

$ chmod u+x hello.sh

シェルスクリプトの基本を叩き込む

以下をひととおり学習しました↓
http://motw.mods.jp/shellscript/tutorial.html

比較演算子の覚え方

-eqは分かるけど、-gtとか-leとかはパッと使いたいけど覚えにくい。。。
英語を知ると少しだけ覚えやすくなりますね!

演算子     英語 意味
eq equal x = y
ge greater than or equal to x >= y
gt greater than x > y
le less than or equal to x <= y
lt less than x < y
ne not equal x != y

実用的なスクリプト作ってみよう

その1:ファイル名を一括リネームする

以下のサイトを参考にしました
http://motw.mods.jp/shellscript/rename.html

その2:バックアップフォルダにファイルやフォルダをコピーする

こちらは自分で考えて作成してみました。

make_bk.sh
#!/bin/bash
read -p "バックアップをとりたいファイル名またはフォルダ名を入力してください:" ary
echo $ary

#入力値がない場合、エラーメッセージを表示し終了する
if [ -z $ary ];
then
  echo "バックアップを取りたいファイル名またはフォルダ名を入力してください"
  exit 1
fi

#バックアップフォルダを作成。-pオプションで、フォルダが存在しないときだけ新規作成される
bkdir=bk_$(date +%Y%m%d)
mkdir -p $bkdir

#入力されたファイルまたはフォルダをひとつづつ読み取る
for target in ${ary[@]}
do
  #コピーを作成し、バックアップフォルダに格納する
  [ -d $target ] && cp -r $target $bkdir/$target || cp $target $bkdir/$target
done

このスクリプトでは、ファイルやフォルダの数を限定していないので、入力を受け付けるときに配列を利用しました。
配列の使い方は、以下を参考にしました。
https://www.atmarkit.co.jp/ait/articles/1905/22/news004.html

以下の部分について。

[ -d $target ] && cp -r $target $bkdir/$target || cp $target $bkdir/$target

cpコマンドでは、フォルダ(=ディレクトリ)をコピーするときは「-rオプション」が必要なため、$targetがディレクトリかどうか判断してからcpコマンドを実行しています。
他に良い方法ありましたらご教示いただけると嬉しいです。

実行してみましょう

その前に、実行権を与えます。

$ chmod u+x make_bk.sh
実行前のフォルダ構成
 tmp
  ├── make_bk.sh
  └── test.txt   //こいつをコピーします

実行します

$ make_bk.sh
バックアップを取りたいファイル名またはフォルダ名を入力してください:test.txt
test.txt
実行後のフォルダ構成
 tmp
  ├── bk_20200329   //新規作成されたフォルダ
  │   └── test.txt  //コピーされたファイル 
  ├── make_bk.sh
  └── test.txt

次は、
フォルダごとコピー&バックアップフォルダが存在している場合は対象をコピーするだけ
を確認します。

実行前のフォルダ構成
 tmp
  ├── bk_20200329
  │   └── test.txt
  ├── make_bk.sh
  ├── test.txt
  └── test2   //こいつをコピーします
      └── test2.txt  //同時にコピーされるはず

実行します

$ make_bk.sh
バックアップを取りたいファイル名またはフォルダ名を入力してください:test2
test2
実行後のフォルダ構成
 tmp
  ├── bk_20200329
  │   ├── test.txt
  │   └── test2          //コピーされたフォルダ 
  │       └── test2.txt  //一緒にコピーされたファイル
  ├── make_bk.sh
  ├── test.txt
  └── test2
      └── test2.txt

おまけ:便利なLinuxコマンド

学習していく中で「便利だな、使いそうだな」と思ったコマンドのメモです。
◆historyコマンド実行時に日時も表示させたい
 参考:https://linuxfan.info/add-datetime-to-history
◆作業ログを記録したい
 参考:https://dev.classmethod.jp/articles/scriptcommand/

おわりに

基本は掴めたはず!何事もやってみるもんですね。
今回の目的はスクリプトに慣れることだったので、作成したスクリプトの実用性を問われるとなんとも言えませんが、
これから作業していく中で「これ自動化したい」「このコマンドまとめられる!?」と思ったときに作れそうな気がするので、時が来るのを楽しみにします、、、
次の段階として、実行速度や再利用性などにも気を遣えるよう勉強していきます…!