1 章. UNIX コマンド・シェルスクリプト1

1.1 序文 - なぜ UNIX コマンドを学ぶか
昨今の基本システムを取り巻く環境は UNIX もしくは UNIX-Like な OS の一強
クラウドサービス
開発環境
モバイルOS...
それらの基本となるインターフェースは?
CUI -> UNIX/LINUXコマンド
2

1.2 前提知識

3

POSIX について
POSIX は UNIX-like OS に定められた共通の仕様について、プログラムの呼び出し方法などの標準を定めた規格
UNIXから派生していろいろなOSが出てくる中で、互換性を保つために定義された
mac / linuxでコマンドの実装が違い、オプションが違うこともあるので適宜調べつつ、資料を読んでいってください。

4

自らを助ける方法

基本的にコマンドの使用方法は以下のコマンドより知ることが出来ます。
man cat5基本的なコマンド

ディレクトリの移動やファイルの移動・削除など
pwd, cd, ls, cp, mv, rm, mkdir...

6

1.3 エンジニアの日常コマンド

7

何かを監視する

アクセスログなど増え続けるログに対して、監視するコマンドたち。
今だとあまり使うことなさそう?(data dogとかあるし)って思ってましたが、最近だとdev環境の状態眺めたり、負荷試験でgatlingサーバが仕事してるかにちょっと使ったりしました。

watch

引数のコマンドを一定期間ごとに定期実行してくれる
watch [options] COMMAND

tail

ファイルの終端部分を見れるコマンド
追記を監視する f/F オプションが便利。
tail [options] [file]8

何かを監視する
試してみる
tempファイルに1秒ごとに追記し続けるシェルがあるので実行してみる。
$ bash test_log.shtarget_file: /tmp/testlog.cxEatailやwatchを使ってみる。
$ tail -F /tmp/testlog.cxEa$ watch tail /tmp/testlog.cxEa

終了するときはCtrl+Cで終了します。
9特定のファイルから特定の文字列だけ検索したい
特定のファイル名一覧を探したり、TODOを含むファイルだけ抽出したり...

find

ファイルやディレクトリ検索
find [path] -name "file_name"grep

文字列を検索し、マッチした行を出力する。
検索文字列

grep [options] "" [file]#
grep -E '[Aa]bc' [file]

正規表現も使える10あるコマンドの出力結果を他のコマンドの入力に使いたい

11標準入出力catなどのコマンドが起動されると、自動的に入出力チャネルが開かれます。
(チャネル: データの流れる経路)
標準入力
標準出力
標準エラー出力

Text terminal#0 stdinProcess

Keyboard#1 stdout#2 stderr

Display

図のように、標準入力にキーボードを使うこともあればファイルを使うこともあります。
また、出力先もdisplayではなくファイルやプリンタ指定することができます。

12リダイレクト

先程の標準入出力先を変更する機能のことをリダイレクトと言います。
自前で作成したファイルをコマンドへの入力に用いたり、コマンド実行による出力の向き先を変更することができます。
例:標準入力を差し替えたい場合
sort < cat example.txt

例: 標準出先を差し替えたい場合
新規作成
ファイル末尾に上書き#ls > example.txt##ls >> example.txt

13

パイプ

パイプを使うことで前のコマンドの処理結果（標準出力）を次のコマンドの標準入力に渡すことができます。
例: カレントディレクトリからファイルを検索し、数を数える。
find . -type f | wc -l

も wc もお互いに関係ない機能ですが、パイプで連携することで1つのまとまった仕事をします。
パイプのおかげで個々のコマンドは小さい機能にまとまることができていて、組み合わせることで期待する動作を実現しています。
find14

xargsは標準入力として引数のリストを与える。
rm コマンドのように、2番目のコマンドのパラメータにパイプの結果を渡したい場合に便利です。
例: ls で出てきたファイル一覧を rm -rf <引数> で処理する.
xargs

ls | xargs rm -rf15

Q. | がなくても < , > だけで十分では？

がなくても command1 > temp_file && command2 < temp_file という風に書くことでパイプと同じことはできます。
しかしこのような処理に置いて、 temp_file は本来意識しなくてもいいことの方が多いので、同じ処理を書くのであれば | の方が見通しが良くなります。
|Pipes are used to create what can be visualized as a pipeline of commands,

パイプは、コマンドのパイプラインとして視覚化できるものを作成するために使用されます

http://www.linfo.org/pipe.html

16

演習

1. assetsフォルダの中にあるテキストファイル(*.txt)の数を数えるワンライナーを作成せよ。

2. assetsフォルダの中にあるテキストファイル(*.txt)にある「客」という単語数を数えるワンライナーを作成せよ。
(ヒント: grepのo, hオプション)
173. (発展) 2番はgrepのオプションを使うことで簡単に実現することができるが、POSIX準拠
ではないオプションなので他のOSでの動作は保証できない。grepのオプションなしで実現せよ。
4. (発展) assetsフォルダの中にあるテキストファイル(*.txt)にある各文字の数を数え上げる
ワンライナーを作成せよ。
アウトプットイメージ:
より客柿食

1515
30
15
15...

18

その他01sort
printf "123\n456\n123\n" | sort

uniq

ソート済みテキストを unique なもので集約する
printf "123\n456\n123\n" | sort | uniq

19

その他02cut

特定の区切り文字で分けられた単語を切り出す。
printf "aaa bbbb\nccc bbbb\n" | cut -d' ' -f1

sed

入力を置換する
echo hogehogehoge | sed s/hoge/aaa/#echo hHHHHHello | sed -E "s#[Hh]+ello#Konnichiha#"

正規表現も使える

20

1.4 シェルスクリプト

シェルのコマンドラインを予め記述しておくファイルのこと
利点として以下が挙げられる。
一度シェルスクリプトを作成すれば再利用することができる
他人へ配布して使用してもらえることができる
コマンド打ちミスによる作業ミスがなくなる
そのため、定期的に実行するコマンドやシステムのセットアップなどのコマンドはシェルスクリプトとしてまとめられていることが多いです。
21

shebang

まずはシェルスクリプトの先頭行にインタプリタを明示しましょう。
#!/bin/sh のような実行するシェルスクリプトを書いた行のことを「shebang」と言います。
下記の例だとbashにシェルスクリプトを実行させるという意味になります。
#!/bin/bash#

以下にシェルスクリプトを書く

様々な環境でスクリプトが実行されることを考えると、shebangに明記しておかないと思わぬところでエラーが発生したりします。
(bash特有のpushdとか)22

変数

シェルスクリプトでは変数を定義して代入したりそれを演算に用いることができます。
(これらの変数に型は存在しません。)
スクリプト内で多用するファイルのPATHやコマンド名などは変数にしてファイル先頭にまとめておくと使い回しやスクリプト改造の際に扱いスクリプトとなります。
HOGE=HOGE=100
HOGE=hoge

1行目が定義、2行目が代入、3行目が再代入になります。
定義が必要なければ2行目から実行しても大丈夫です。
ここで変数には2種類あることを留意しましょう。

23

シェル変数

そのシェル上で定義されている変数のこと。上記の例はシェル変数を定義していることになります。
現在定義されている変数を確認するには set コマンドを引数なしで実行します。

24

環境変数

あるシェルプロセスでシェル変数を定義したとしても、そのシェル上で更にプロセスを開始してもそのプロセスではシェル変数は引き継がれません。
子プロセスでも変数を引継ぎ可能にするためには環境変数として変数を定義すると良いです。
export HOGE=100

現在の環境変数が何かは env コマンドで確認できます。
よく ~/.bashrc などに記述される変数は export HOGE=hoge などとされていますが、これはユーザー bash を立ち上げてその下で立ち上がるプロセスでも使いたい変数のため、環境変数を用いています。
25

デフォルト値

以下の部分ではデフォルト値を設定しながら変数を定義している。
TARGET=${1:-test.com:6565}

デフォルト値を使わないコードは以下となる。
TARGET=$1

つまり、第一引数がある場合はそちらを代入, なければデフォルト値を使用するというコードになっており、使い回しやすいスクリプトとなっている。
26

エラーや未定義変数による停止

変数定義終わりに set -u のコマンドが見えます。
u オプションは、未定義変数があった場合にエラーとするオプションです。
set -u 以降のコマンドは未定義変数があった場合、エラーとして処理が終了します。
同じ用途でもう一つよく使われるオプションとして、 e オプションがあります。
set -e をすると、エラーあった場合に、シェルスクリプトをそこで終了させます。
27

終わりに今回の講義では基本的なUNIXコマンドとシェルスクリプトについて学びました。
基本的なコマンドは「そういうのがあるんだ」という状態になっておけば、今後必要そうな時に調べて使いこなせると思うので是非いろいろ調べてみてください。
シェルスクリプトに関しては、身近な参考
file /bin/* | grep "shell script"

28

その他

29終了コード

終了コードとは、プロセスが終了した時のステータスを表す整数値のこと。
一般的には0が正常終了、それ以外が異常終了とされるのが慣習的となります。
シェルスクリプトでは $? という特殊変数に、最後に実行したコマンドの終了コードが格納されています。
この特殊変数を test コマンドを合わせて条件判定する処理をすることはよくあるように思われます。
if [ $? -ne 0 ]; thenecho "OH MY GOD!!"
exit 1fi30

if

ifは与えられた条件式の終了ステータスが0である場合はtrue, それ以外である場合はfalseとして捉えて条件分岐処理を行うコマンドである。一般的なifの使い方を以下に示す。
条件式1 ; then
処理1
elif 条件式2 ; then
処理2
else
処理3iffi31

ifもコマンドの一つであるため、ifと条件式1の間に必ずスペースを入れなければならないことに注意したい。
条件式には test コマンドが用いられることが多いが ls , grep などの一般的なコマンドが終了ステータスを返すことに変わりはない。例えば以下の条件式は file が存在(Exist)していれば終了ステータス0を返す。
test -e file32

[と [[

でできることは test コマンドと同じである。 [ を用いて test -e file と同じ動作をするコマンドを以下に示す。
[[ test - e file ]と違う点は 条件式の最後に ] を含める必要があるという点である。
[[ はbashで用いることのできるtestで、 [ よりもできることが増えている。
詳しくは https://www.gnu.org/software/bash/manual/bash.html を参照されたい。
test33

バックグラウンド実行
top, ping のようなコマンドを実行するとターミナル前面で実行結果が常に表示され、C-cで抜け出すなどしてプロセスを終了するまでは他にコマンドを叩くことができない。
これはフォアグラウンドでプロセスが実行されているからである。
そうではなく裏側でこれらのコマンドを実行していて欲しい場合は、ping google.com & というようにコマンドの最後にアンパーサンドを置くことでバックグラウンドでの実行が可能になる。
GUIを備えたLinux OSで emacs と打ち込んで立ち上げるとemacsのGUIが立ち上がるが、この際もフォアグラウンド実行となるので、 emacs & としてバックグラウンド実行とすることで、emacsを使いながらターミナルも使えるようになる。
バックグラウンド実行したプロセスの状態を利用したコマンドがいくつかあるのでそれらを紹介する。

34

wait

は現在実行しているシェルで動かしているジョブが全て終了するまで、次の処理をブロックすることができる。
wait#!/bin/bash
command1 &command2 &wait
command3

補足

プロセス
カーネル(OS)が管理しているプログラムのこと
ジョブ
シェルが管理しているプログラムのこと

35

nohupnohup は "NO Hung UP" の略で、ターミナルを閉じたりログアウトしてもプロセスを殺さないようにしてくれる。
例えばmacで下記コマンドを試すと、ターミナルを閉じてもpingが投げ続けられる。
nohup ping google.com &実行結果は nohup.out に投げ続けられるので、 改めてターミナルを立ち上げ直して tail f するなどして確認できる。
[1] 56107
sh-3.2$ appending output to nohup.out

36名前付きパイプ

先述のパイプは一般的な考え方としてキューとして捉えることができる。つまり、command1で先に出力したもの
mkfifo fifo
echo 'hello named pipe' > fifo

別ターミナルを立ち上げて下記を実行。
cat fifo37

参考(2次情報も混ざっていてすみません..)

https://www.atmarkit.co.jp/ait/articles/1708/04/news015.html
https://qiita.com/ine1127/items/5523b1b674492f14532a
https://shellscript.sunone.me/if_and_test.html
https://qiita.com/akym03/items/aadef9638f78e222de22
https://qiita.com/Ping/items/f9b5175085026462b082#fn2
https://www.atmarkit.co.jp/ait/articles/1708/24/news022.html
https://www.atmarkit.co.jp/ait/articles/1906/28/news025.html
38https://shellscript.sunone.me/for.html
https://www.atmarkit.co.jp/ait/articles/1708/04/news015.html
https://shellscript.sunone.me/while.html
https://eng-entrance.com/linux-redirect
https://qiita.com/jpshadowapps/items/d6f9b55026637519347f
https://www.gnu.org/software/bash/manual/bash.html
https://eng-entrance.com/linux-pipeline
https://shellscript.sunone.me/exit_status.html
39https://qiita.com/toshihirock/items/78286fccf07dbe6df38f
https://qiita.com/Takatoshi_Hiki/items/4e89ae3cf51794d8a96f#ジョブとは
http://wordpress.honobono-life.info/lin-base/プロセス階層、プロセスグループ、セッションを/http://web.sfc.keio.ac.jp/~manabu/command/contents/pipe.html
https://ja.wikipedia.org/wiki/Wait
https://linuxjm.osdn.jp/html/LDP_man-pages/man2/syscalls.2.html
40https://ja.wikipedia.org/wiki/終了ステータス
http://itdoc.hitachi.co.jp/manuals/3021/3021313340/JPAS0409.HTM
https://udzura.hatenablog.jp/entry/2019/10/15/231632
https://haystacker.net/linux-pipe-deep-dive/
入門UNIXシェルプログラミング改訂第2版
シェルプログラミング実用テクニック

41