- 投稿日:2020-10-14T22:36:58+09:00
shell scriptの基本的な構文メモ
目次
- 変数、特殊変数
- 配列
- 数値計算
- if
- 文字列の比較
- for, while
- case & select
- 関数
変数、特殊変数
変数
read -p "Pick 3 colors: " c1 c2 c3 echo $c1 echo $c2 echo $c3特殊変数
echo $0 echo $1 echo $2 echo $# echo $@./test a b c ./test a b 3 a b c配列
colors=(blue red green) echo "${colors[@]}" echo "${colors[0]}" colors+=(pink white) #配列の足し算 echo "${colors[@]}"blue red green blue blue red green pink white数値計算
# + - * / % ** ++ -- n=1 ((n++)) #n=2 ((n=n+5)) #n=7 echo $n ((n=n/7)) #n=1 echo $nif
read -p "name :" name if [[ $name == "mhori" ]]; then echo "welcome" elif [[ $name =~ ^m ]]; then #mから始まるとき echo "Are you mhori?" else echo "you are not allowed" fiファイルやディレクトリがあるかどうか
read -p "searching name:" name if [[ -f $name ]]; then echo "file $name exists" elif [[ -d $name ]]; then echo "directory $name exits" fi文字列の比較
# = == != -z(文字列の長さが0) =~(正規表現) read -p "string: " str if [[ -z $str ]]; then echo "string is empty" elif [[ $str =~ ^m ]]; then echo "string starts with m" else echo $string fifor, while
for
colors=(blue red pink) for color in ${colors[@]}; do echo "I love $color" doneI love blue I love red I love pinkwhile
i=0 while ((i < 10)); do ((i++)) if ((i == 3)); then continue elif ((i == 6)); then break fi echo $i done1 2 4 5while無限ループで読み込み続ける
while : do read -p "command : " cmd if [[ $cmd == "quit" ]]; then break else echo $cmd fi donecommand : p p command : m m command : qiot qiot command : quitファイルから読み込む
1行ずつ読み込んで出力する
## 1 ## while read line; do echo $line done < colors.txt ## 2 ## cat colors.txt | while read line do echo $line donecase & select
case
read -p "Signal color : " color case "$color" in red) echo "stop" ;; blue|green) echo "go" ;; *) echo "wrong signal" esacselect
select color in red blue green yellow ; do case "$color" in red) echo "stop" ;; blue|green) echo "go" ;; yellow) echo "caution" ;; *) echo "wrong signal" break esac done1) red 2) blue 3) green 4) yellow #? 1 stop #? 2 go #? 3 go #? 4 caution #? 0 wrong signal関数
終了ステータスの確認
Unixでは0が正常終了、1が異常終了で、
$?
で調べることができるのを知っておくと便利。hello() { if [[ $1 == "mhori" ]]; then echo "hello $1" return 0 else echo "goodbye $1" return 1 fi } hello mhori; echo $? #hello mhori 0 hello mmm; echo $? #goodbye mmm 1
- 投稿日:2020-10-14T21:47:19+09:00
よく使うコマンドラインショートカットキー(Mac)
行頭へのカーソル移動
- Ctrl + f
- 前方に一文字移動する
- Ctrl + a
- 行頭へ移動する
- エスケープの後、f
- 前方に一単語分移動する
行末へのカーソル移動
- Ctrl + b
- 後方に一文字移動する
- Ctrl + e
- 行末へ移動する
- エスケープの後、b
- 後方に一単語分移動する
文字の削除
- Ctrl + h
- 後方1文字削除
- Ctrl + d
- カーソル位置1文字削除
- Ctrl + w
- 後方スペース区切りで1単語削除
カットアンドペースト
- Ctrl + k
- カーソル位置から行末までカット
- Ctrl + u
- カーソル位置から行頭までカット
- Ctrl + y
- ペースト
画面を消去
- Ctrl + l
- 画面を消去
- 投稿日:2020-10-14T18:03:05+09:00
【shell】コマンドで任意のファイルをZip圧縮してファイル作成して元ファイルを削除する。
- 投稿日:2020-10-14T13:06:49+09:00
yumとaptの update / upgrade の違い
結論
yum update
とapt update
の挙動は違います。※upgrade
も違い
コマンド yum (RedHat系:CentOSなど) apt(Debian系:Ubuntuなど) update インストール済みのパッケージをアップデート インストール可能なパッケージの「一覧」を更新
パッケージ自体は更新されていないupgrade パッケージのアップデート(yum update)
+不要になったパッケージの削除パッケージ構成を変えない範囲でアップグレードする
不要なパッケージの削除、カーネルの更新はしない
「一覧」が古い(apt updateをしていない)と、古いパッケージを元に更新が実行されるdist-upgrade なし パッケージ構成の変更に追随してアップグレード(yum upgradeと同じ?) 経緯
yum
とapt
の挙動は同じだと無意識に思っていた。
CentOSやUbuntuでupdateしたときに、挙動が違ったためメモ。
- 投稿日:2020-10-14T13:06:49+09:00
yumとaptの update / upgrade は違う
結論
yum update
とapt update
の挙動は違います。※upgrade
も違い
コマンド yum (RedHat系:CentOSなど) apt(Debian系:Ubuntuなど) update インストール済みのパッケージをアップデート インストール可能なパッケージの「一覧」を更新
パッケージ自体は更新されていないupgrade パッケージのアップデート(yum update)
+不要になったパッケージの削除パッケージ構成を変えない範囲でアップグレードする
不要なパッケージの削除、カーネルの更新はしない
「一覧」が古い(apt updateをしていない)と、古いパッケージを元に更新が実行されるdist-upgrade なし パッケージ構成の変更に追随してアップグレード(yum upgradeと同じ?) 経緯
yum
とapt
の挙動は同じだと無意識に思っていた。
CentOSやUbuntuでupdateしたときに、挙動が違ったためメモ。
- 投稿日:2020-10-14T10:22:09+09:00
Linux 一般ユーザーへのsudo 権限付与
1「wheel」グループに「abcde」ユーザーを追加します。
usermod -G wheel abcde2visudoを編集
visudo3コマンドの意味を理解しましょう
## Allow root to run any commands anywhere root ALL=(ALL) ALLroot rootユーザーは
ALL= 全てのホストから
(ALL) 全てのユーザーとして実行でき
ALL 全てのコマンドが実行できる
```4rootではなくwheelグループに対して権限を追加します
先頭の「#」を外してこの行を有効にします。
# Allows people in group wheel to run all commands %wheel ALL=(ALL) ALL5 権限が効いてるか確認します。
rootをログアウトしてabcdeユーザでログインします。
ここではcatで実行が許可されていないコマンドを実行してみましょう。
通常の方法では権限がないためabcdeユーザで実行しても「許可がありません」とエラーが表示されます。cat /var/log/secureでは続いてsudoを最初に用いて同じコマンドをたたいてみましょう。
sudo cat /var/log/secure実行できていれば権限付与終了です
- 投稿日:2020-10-14T00:30:26+09:00
なるほどUNIXプロセスを読んでいく
※途中です。
- RubyのあらゆるところはUnixのシステムコールや文化・思想を反映している。
- Rubyを使うことで、低レベルなことは言語に任せて、Unixそのものの考え方を学ぶことができる。
第1章 はじめに
- すべてのコードはプロセスの上で動いている。
- トラフィックとリソースが逼迫してくると、アプリケーションコード以外も見なければならない。
第2章 本書の手引き
Unixプログラミングの考え方とその技術は、この先の40年でも役に立つ。
システムコール
- プログラムは直接カーネルを操作できず、すべてシステムコール経由でなければならない。
- システムコールのインターフェースがカーネルとユーザーランドとを取り次ぐ。
- ユーザーランド
- 自分が書いたプログラムが実行される場所。
- 算術演算や文字列操作、論理演算に基づいた処理の流れの制御。
- カーネル
- コンピュータのハードウェアの頂点に位置し、ハードウェアを制御するための中間層。
- ファイルシステムの読み書きやネットワークを介したデータのやり取り、メモリのアロケートやスピーカーでの音楽再生などの制御。
man ページ
- Unixプログラミングを学ぶ上で適切なドキュメントが全て載っている。
- 以下のような状況下で参考となる。
- Cでプログラムを書いていて、システムコールの使い方を調べたいとき。
- あるシステムコールの目的を理解したいとき。
man ページのセクション
- 誰もが実行できるユーザーコマンド(シェルコマンド)
- システムコール(カーネルが提供する関数)
- サブルーチン(Cライブラリ関数)
- デバイス(/dev ディレクトリのスペシャルファイル)
プロセス: Unixの原子
- あらゆるコードはプロセス上で実行される。
- コマンドラインからrubyを起動すると、コードを実行するための新しいプロセスが生成される。コードを実行し終わったら、プロセスは終了する。
- MySQLサーバの専用プロセスが動き続けていることにより、MySQLサーバがずっと起動し続けている。
第3章 プロセスにはIDがある
pid
- システムで動作するすべてのプロセスが持つ固有の識別子(プロセスID)
- プロセスにまつわる情報は何も持たない、単に連番になっている数値のラベル。
相互参照
- ps(1) コマンド
- pidがカーネルから見ている情報を相互参照する。
- ログファイルで多く見かける。
- 1つのファイルに複数のプロセスのログを取っている場合、ログファイルの各行がどのプロセスから出力されたものかを識別できねばらならない。ログの各行にpidを含めておけば、この問題を解決できる。
OSの提供する情報と相互参照できるコマンド
- top(1)
- 実行中のプロセスをリアルタイムで表示する。
- lsof(8)
- list open files。オープンしているファイルを一覧表示。
第3章 プロセスには親がいる
すべてのプロセスには親となるプロセスがいる。
ppid
- 親プロセスのppid。
親プロセス
- そのプロセスを起動したプロセス。
例
- Mac OSXで「Terminal.app」を起動したら、bashのプロンプトが表示される。
- 全てはプロセスなので、この動作はすなわち、「Terminal.app」のプロセスを開始して、それからbashプロセスを開始したということ。
- この時、bashプロセスの親プロセスは「Terminal.app」のプロセスになる。
- bashプロンプトからls(1)コマンドを実行したなら、lsプロセスの親プロセスはbashプロセス。
実用例
- 現実にppidを利用するケースはそう多くはなく、デーモンプロセスを検知したい場合には重要になることがある。
第5章 プロセスにはファイルディスクリプタがある
実行中のプロセスをpidで表すのと同じように、開かれたファイルはファイルディスクリプタとして表す。
すべてはファイルである
- Unix哲学の一つ。
- デバイス、ソケット、パイプ、ファイルなどはすべてファイルとして扱われる。
ディスクリプタはリソースを表す
- 実行中のプロセスでリソースを開くと、ファイルディスクリプタ番号が割り当てられる。
- ファイルディスクリプタは関連しないプロセス間では共有されない。
- リソースを開いたプロセスが終了すると、ファイルディスクリプタも閉じられる。
ファイルディスクリプタはプロセスとともに生き、プロセスとともに死ぬ運命にある。
Rubyでは、開いたリソースはIOクラスで表現される。すべてのIOオブジェクトは自身に割り当てられたファイルディスクリプタ番号を知っている。
- IO#filenoを使うと、ファイルディスクリプタ番号を取得できる。
ファイルディスクリプタ番号は未使用の小さい整数から順に割り当てられていく。
リソースが閉じられると、そこに割り当てられていたファイルディスクリプタ番号は再び利用可能となる。
標準ストリーム
- すべてのUnixプロセスには3つの開かれたリソースがついてくる。
- 標準入力(STDIN)
- 標準出力(STDOUT)
- 標準エラー出力(STDERR)
STDIN
- キーボードデバイスやパイプといった入力からの読み込み全般のための方法を提供している。
STDOUT、 STDERR
- モニタやファイル、プリンタといった出力先への書き込み全般のための方法を提供している。
実用例
- ファイルディスクリプタは、ソケットやパイプを使ったネットワークプログラミングの肝となる。
第6章 プロセスにはリソースの制限がある
1プロセスあたりどれくらいのファイルディスクリプタを持てるのだろうか?
- システムの設定による。
カーネルによって1プロセスごとにリソースの制限が設定されている。
第7章 プロセスには環境がある
環境変数
- キーとバリューが対になっており、プロセスで使えるデータを保持している。
すべてのプロセスは親プロセスから環境変数を引き継ぐ。
- 環境変数は親プロセスによって設定され、子プロセスに引き継がれる。
- 環境変数はプロセスごとに存在し、それぞれのプロセスではグローバルにアクセスできる。
ENVはEnumerableやHashのAPIを部分的には実装しているが、Hashと全く同じ機能は揃えていない。
実用例
$ RAILS_ENV=production rails server $ EDITOR=mate bundle open actionpack $ QUEUE=default rake resque:work
- 環境変数はコマンドラインツールに入力を渡す方法としてよく採用される。
第8章 プロセスには引数がある
ARGV
- Rubyプロセスが参照できる特別な配列。
argv
- argument vector。引数の配列。
- コマンドラインからプロセスに渡された引数が格納されている。
$ cat argv.rb p ARGV $ ruby argv.rb foo bar -va ["foo", "bar", "-va"]
ARGV = Array
- 引数は配列であり、要素の追加や削除もできれば、格納されている要素の内容も好きなように変更できる。
- コマンドラインから渡された引数をオブジェクトとして表現したもの
- よって実際に変更を迫られるような機会はそう多くはない。
実用例
- プログラムにファイル名を渡したい場合。
- 1つまたは複数のファイル名をコマンドラインから受け取って、そのファイルを処理するプログラムを書く場合など。
- コマンドライン引数の解析
第9章 プロセスには名前がある
Unixプロセスには、プロセスの状態を知らせるための手段がほとんどない。
- プログラマによるログファイルの発明。
- ログファイルは、ファイルシステムに書き込むことによって、プロセスが伝えたい情報を何でも共有できる。
- しかしこれは、プロセス自身というよりはファイルシステムレベルでの話。
- ソケットを開いてネットワークを使う。
- プロセスは他のプロセスと通信できるが、ネットワークに依存するため、これもまたプロセスそのもののレベルとは話が違ってくる。
プロセスのレベルで情報を伝える2つの仕組み。
- プロセス名
- 終了コード
プロセス名
- 端末からirbを起動したとすると、プロセスには「irb」という名前が与えられる。
- Rubyでは
$PROGRAM_NAME
というグローバル変数に現在のプロセスの名前が格納されている。第10章 プロセスには終了コードがある
終了コード
- プロセスが終了時にこの世に残す最後のしるし。
終了コード値
- あらゆるプロセスは、正常終了か以上終了かを示す終了コード値(0-255)と共に終了する。
終了コード0
- 正常終了時
- それ以外の終了コードはエラーを示す。
プロセスの終了の仕方
- exit
- exit!
- abort
- raise
Kernel#exit
- 最も簡単な方法。
- 明示的に終了処理をせずにスクリプトを終了した場合も、これと同様の処理が暗黙的に行われる。
Kernel#exit!
- デフォルトの終了コードが異常終了(1)
- Kernel#at_exitで定義されたブロックは実行されない。
Kernel#abort
- 問題のあったプロセスを終了させる場合によく使われる。
Kernel#raise
- raiseで送出された例外が捕捉されない場合も、プロセスを終了させる方法の一つ。
- raiseはプロセスをすぐには終了せず、例外は単に呼び出し元へ向かって送出される。
- 例外がどこでも捕捉されなかった場合、結果としてプロセスが終了することになる。
第11章 プロセスは子プロセスを作れる
fork(2)
- 実行中のプロセスから新しいプロセスを生成できる。
- 新しいプロセスは元のプロセスの完全なコピーとなる。
- Unixプログラミングで最も強力な考え方の一つ。
プロセス生成
- fork(2)を呼ぶ側のプロセスを「親プロセス」、新しく作られるプロセスは「子プロセス」と呼ばれる。
子プロセス
- 子プロセスは親プロセスで使われているすべてのメモリのコピーを引き継ぐ。
- プロセスが巨大なソフトウェアを読み込んだとして、それが500MBのメモリを消費(ex. Railsアプリ)しているとする場合、このプロセスから2つの子プロセスを生成すると、それぞれの子プロセスがメモリ上に巨大なソフトウェアのコピーを効率的に保つことになる。
- forkを使うと、その呼び出しはすぐに戻ってきて、500MBのメモリを消費するプロセスが3つ存在することになる。
- アプリケーションのインスタンスを複数同時に立ち上げたい時、実に便利。
- 親プロセスが開いているファイルディスクリプタも同様に引き継ぐ。
- 子プロセスのファイルディスクリプタ番号は親プロセスと同じものが割り当てられている。
- そのため、2つのプロセスで開いているファイルやソケットなどを共有できる。
- まったく新しいプロセスなので、固有のpidが割り当てられる。
- ppidはfork(2)を実行したプロセスのpidとなっている。
- 子プロセスがコピーしたメモリは、親プロセス側に影響を与えることなく自由に変更できる。
forkメソッド
- forkメソッドは1回の呼び出しで、実際には2回返ってくる。
- forkは新しいプロセスを生成するメソッド!
- 片方は呼び出し元の親プロセスに、もう片方は生成された子プロセスに返ってくる。
# if文のif句とelse句の両方が実行されている # 親プロセス側では生成した子プロセスのpidが返り、子プロセス側ではforkはnilを返す。 if fork puts "entered the if block" else puts "entered the else block" end => entered the if block entered the else block
forkはマルチコアプログラミングか
- 新しく生成したプロセスが複数のCPUコアをまたいで(並列で)分散処理できればそうなるが、必ずマルチコアで処理されるという保証はない。
- 例えば、4個のCPUのうち、4つのプロセスがすべて単一のCPUで処理されることもありうる。
ブロックを使う
- Rubyでよく使われるのは、forkにブロックを渡すやり方。
- ブロック付きでforkメソッドを呼び出した場合、ブロックは子プロセスのみで実行されて、親プロセスでは無視される。
- 子プロセスはブロック内の処理が終わったらそこで終了する。親プロセスの処理は続行しない。
fork do # 子プロセスで実行する処理をここに記述する end # 親プロセスで実行する処理をここに記述する第12章 孤児プロセス
第13章 プロセスは優しい
第14章 プロセスは待てる
第15章 ゾンビプロセス
第16章 プロセスはシグナルを受信できる
第17章 プロセスは通信できる
第18章 デーモンプロセス
第19章 端末プロセス
第20章 おわりに