コマンドの実行は「シェル」を介して行なっています
「シェル」には「対話的なつかい方」と「シェルスクリプトを書いて実行するつかい方」があります
シェルについて
プログラムを実行するにはカーネル(OSの中核)とやり取りする必要があります
利用者がカーネルとやり取りするには「シェルというソフトウェア」が必要です
「シェル」は「利用者とカーネルの仲介役」として「対話的(インタラクティブ)」に「利用者の要求」に対して「必要な処理を実行」します
「シェル」がコマンドを実行すると「プロセス」が立ち上がります
複数の「シェル」を起動することができ、新しく起動したシェルは「現在のプロセス」の「子プロセス」になります
シェルのおもな役割
- シェルコマンドの実行
- プログラムの起動・停止・切り替え
- ファイルの操作
- コマンドの入力履歴の保存
- コマンドの補完
「カーネルとシェル」「プロセス」についての参考
シェルの種類について
「bash・sh・zsh・ksh・csh・tcshなど」さまざまな種類があり「bash」が多くのLinuxディストリビューションで標準的につかわれています
*種類によって多少の差異があります(設定ファイル名が異なります)
ここでは「bash」をつかいます
変数には「シェル変数」と「環境変数」があります
「利用する値」を「変数に格納」し「値を利用するとき」に「変数を参照」します
「シェル変数」は「変数を宣言したシェル」でのみ参照でき「子プロセス」からは参照できません
「環境変数」はすべてのプロセスで有効な変数で「子プロセス」からも参照できます
コマンドラインの入力 | 内容 |
変数名=値 | シェル変数の定義 |
export 変数名=値 | 環境変数の定義 |
echo $変数名 | 値を表示 |
bash | 対話型シェル(子プロセス)の起動 *シェルには「ログインシェル」と「対話型シェル」があります 詳細はあとで |
exit | シェルの終了 |
unset 変数名 | 変数の削除 |
set | シェル変数と環境変数両方の一覧 |
env | 環境変数の一覧 |
printenv 変数名 | 指定した環境変数のみ表示echo $変数名 でもOK |
(注意)変数の宣言では「=」の前後にスペースをあけない
*スペースをあけるとコマンドとして解釈されてエラーになります
代表的な環境変数
変数名 | 内容 |
PATH | コマンドなどの置かれているパス *PATH変数に「 /bin 」などが登録されているから、コマンド名だけで実行できます |
HOME | 現在の利用者のホームディレクトリ |
PWD | カレントディレクトリ |
PS1 | プロンプト(入力まちで表示されるカーソルの前の短い文字や記号) |
LANG | 使用する言語 |
(余談)PATHという環境変数について
エイリアス(別名)について
「aliasコマンド」は、長いコマンドなどに「別名をつけて」入力を簡素化できます
*「シェル変数」と同じく「aliasを設定したシェル」でのみ参照できます(つねに利用するには、「対話型シェル起動時にも読み込む設定ファイル」に記載します)
コマンドラインの入力 | 内容 |
alias 別名='コマンド' | コマンドに別名をつける |
alias 別名 | コマンドの確認 |
\(または¥)別名 | 別名を一時無効にする |
unalias 別名 | 別名の削除 |
unalias -a | 別名をすべて削除 |
Bash環境のカスタマイズ
「環境変数の定義」や「エイリアス(別名)の登録」は、ターミナルを終了するとリセットされます
しかし
シェル起動時に読み込む「特別な設定ファイル」に「Bash環境を記載する」ことで、ユーザ専用の「環境変数の設定」「エイリアス(別名)の登録」が永続的になります
ようするに、「Bash環境のカスタマイズ」ができます
ややこしいのはw
「特別な設定ファイル名」が複数あり「ログインシェルか?対話型シェルか?」「対象が全ユーザか?各ユーザか?」で「記載する設定ファイル名」や「設定ファイルを読み込む順番」がことなります
*ディストリビューションでも差異があります
「ログインシェル」と「対話型シェル」について
ざっくりw
ユーザがログインした後に「最初に起動されるシェル」が「ログインシェル」
ログイン後「bash
で起動されるシェル」が「対話型シェル」
「ログインシェル」になる場合
*「ログインシェル」のおもな役割は、各ユーザの環境を「シェル」にセットすることです
su -ユーザ名
でシェルを起動したときbash --login
でシェルを起動したときssh
でログインしたとき
「対話型シェル」になる場合
bash
でシェルを起動したときsu ユーザ名
でシェルを起動したとき- デスクトップ環境でターミナルを起動したとき
「ログインシェル」「対話型シェル」の確認方法
*echo $0
で
「-bash」と表示されたときは「ログインシェル」
「bash」と表示されたときは「対話型シェル」
話しがそれますが…デスクトップ環境について
「CUI」と「GUI」のちがい
「CUI」は「キーボード」ですべての操作をする画面
「GUI」は「WindowsやMac」のような「グラフィカルなデスクトップ環境」です
Linuxはコマンドを入力して実行する「CUI」が基本ですが、もちろん「グラフィカルなデスクトップ環境(GUI)」も使えます
(余談)「LinuxのGUIを実現しているアプリケーション」が「X Window System」で「Linuxの統合デスクトップ環境」では「GNOME」「KDE」が有名です
「Linuxのデスクトップ環境」でターミナルを起動したときは「対話型シェル」になります
(余談)Macでターミナルを起動したときは「ログインシェル」なので、???になりました^^;
LinuxでGUI環境がインストールされているときは「GUI」と「CUI」を切りかえできます
- UbuntuでGUIからCUIに切りかえるとき、
Ctrl+Alt+F1
・Ctrl+Alt+F7
で元のモードに戻る - CentOSで切りかえるとき、
init 3
(CUIモード)・init 5
(GUIモード)
話しを戻し、「シェル起動時に読み込む設定ファイル」について
「~/.bashrc」は「環境変数」と「エイリアス」どちらも読み込みます
「ログインシェル」でないときは「.bashrc」を読み込み、ログインシェルのときは「.bash_profile」内で「.bashrc」を読み込むように設定されています
「~/.bashrc」に書き込む
標準出力で設定ファイルに追記する(viで編集してもいい)
# 環境変数
echo "export PATH=$PATH:/追加するディレクトリ(絶対パス)" >> ~/.bashrc
# エイリアス
echo "alias 別名='コマンド'" >> ~/.bashrc
# 現在のシェルで実行する
source ~/.bashrce
*「sourceコマンド」設定ファイルを実行(読み込む)する理由は、設定ファイルは起動時にしか読み込まないからです
「~/.bashrc」は便利ですが、とはいえ、設定ファイルの詳細について💦
「ユーザ用」設定ファイル
すべてのファイルは、ユーザのホームディレクトリ直下(~/)にあります
- ~/.bash_profile
- ログイン時・読込順 2
- ~/.bash_login
- ログイン時・「~/.bash_profile」が存在しないときに読み込む
- ~/.profile
- ログイン時・「~/.bash_profile」「~/.bash_login」が存在しないときに読み込む
- ~/.bashrc
- ログイン時・読込順 3
- 対話型シェル起動時(エイリアスの設定)・読込順 1
「全てのユーザが対象」設定ファイル
(/etc/)ホームディレクトリ直下にあります
- /etc/profile
- ログイン時・読込順1
- /etc/bashrc(RedHat系のみ)
- ログイン時・読込順 4
- 対話型シェル起動時(エイリアスの設定)・読込順 2
- /etc/bash.bashrc(Debian系のみ)
- ログイン時・読込順 1.5
- 対話型シェル起動時(エイリアスの設定)・読込順 0.5
ユーザ用その他の設定ファイル
- ~/.bash_logout
- ログアウト時に実行することを記載
- ~/.bash_history
- コマンドの実行履歴を保存
シェルスクリプト
あらかじめ「実行したいコマンド」をファイル(シェルスクリプト)に書き「まとめて実行」します
*シェルスクリプトの書き方はシェルの種類で差異があります
「cat /etc/shells
」で「シェル一覧」が表示されます(「bash」をつかいます)
作成と実行の基本
「シェルスクリプトのファイル名の末尾」には「.sh」をつけます
ファイルの先頭にシバン「#! /bin/bash」を書きます(処理するシェルを指定するための記述)
シェルスクリプトの実行方法
- 「source」コマンドを使う
source hoge.sh
(「source」は「.」でもいい. hoge.sh
)
シバンは無視され、現在の環境下(bash)で実行されます(主に設定ファイルの読み込みにつかう) - bashシェルを起動して引数に指定する
bash hoge.sh
シバンは無視され、新しいbashシェル環境で実行されます - ファイルに実行権をつけて直接実行
./hoge.sh
シバンが読み込まれ、新しいシバンで指定した環境下で実行されます
シェルスクリプトファイルのパーミッションについて
初期設定で最初にファイルを作成した場合は、実行権限はついていません
ファイルに実行権をつけて直接実行するには
「chmod a+x ファイル名
」や「chmod 755 ファイル名
」で権限を変更します
*3つの方法すべてに「読み取り権限」は必要です
シェルスクリプトファイルの中身(基本)
- 処理の終了
exit 0
(成功)exit 1
(失敗)- このあとに書いた処理は実行されない
- 変数の定義
変数名='文字列'
: 文字列を変数に格納変数名=`コマンド`
または変数名=$(コマンド)
:コマンドの実行結果を変数に格納
- 変数の表示
echo $変数名
- 配列の作成
配列名=('文字列1' '文字列2' '文字列3')
- 配列の表示
echo ${配列名[@]}
: 値をすべて表示echo ${配列名[0]}
: インデックス「0」の値を表示echo ${!配列名[@]}
: インデックスを表示echo ${#配列名[@]}
: 要素の数を表示
- 配列に値を追加・配列の値を削除
配列名[インデックス]='追加する値'
: インデックス番目に値を追加unset 配列名[インデックス]
:インデックス番目の値を削除
- 引数の表示
echo $1 $2
…$n : $1が第一引数・ $2が第二引数 ・$n(n番目の引数)echo $0
: ファイル名を表示echo $@
: すべての引数を表示echo $#
: 引数の数を表示$?
:直前に実行したコマンドの戻り値(0は成功)
- 標準入力から値を受け取る
read 値名
:
受け取った値の処理は$値名
(例えば変数に格納、変数名=$値名
)read -p '説明文' 値名
: 説明文をつけるread -s 値名
: シークレットモードread 値名1 値名2 値名3
:複数の値を受け取ることも可能
(配列で受け取る場合は-a
オプションをつける)
- 結果をファイルに標準出力する
> ファイル名
: 上書き>> ファイル名
: 追加
- コマンドの区切り
;
: 複数のコマンドを順に実行したいときはコマンドの間に「;」を挿入する。
*コマンドの出力結果を次のコマンドに渡さない
(余談)「|
」はコマンドの出力を次のコマンドの入力として渡します
- シェルスクリプトを実行する
.
: 後ろに指定したシェルスクリプトを実行します
プロセスは現在のシェル上で動作します(新たなプロセスは作成されません)
「unsetコマンド」は変数や関数そのものを削除します
unset [オプション] 変数や関数の名前
オプション | 内容 |
-f | 関数名として扱う |
-v | 変数名として扱う |
引用符の種類と内容
種類 | 内容 |
' ' | すべて文字列とみなされる |
" " | 変数は展開される |
` ` | コマンド結果が展開される |
シェル変数はすべて文字列扱いであるため、数値計算のためには専用のコマンドをつかいます
四則演算(計算)を実行して、結果を文字列に展開する
「$((….))」 または「$(expr ….)」をつかいます
*変数を利用する場合
$((num1+num2)) :「変数の前の$」は不要
$(expr $num1 + $num2) :「変数の前に$」が必要
内容 | 書き方 |
足し算(1+1) | $((1+1)) $(expr 1 + 1) *+の前後のスペースをあける |
引き算(1-1) | $((1-1)) $(expr 1 - 1) |
掛け算(1*1) | $((1*1)) $(expr 1 \* 1) *「\(エスケープ)」が必要 |
割り算(1%1) *小数点以下は切り捨て | $((1\1)) $(expr 1 / 1) |
余り(1%1の余り) | $((1%1)) $(expr 1 % 1) |
「bcコマンド」は、対話的に計算を行うコマンドです
length=数値:有効桁数を指定
scale=数値:小数点以下の有効桁数を指定
bc -l : 標準数学ライブラリを読み込んで起動する
#10/3の結果を小数点10桁表示
bc
scale=10
10/3 #小数点10桁
#コマンドを終了
quit
bc -l
10/3 #3.33333333333333333333
# コマンドラインから(文字列(1+0.5)をbcに渡す)
echo "1+0.5" | bc
シェルスクリプトで
2つの引数の割り算結果を小数点10桁まで表示する
*小数点以下をあつかう
#!/bin/bash
echo "scale=10;$1/$2" | bc
条件分岐
「if文」は与えられた条件式が真のときのみ処理を行います
if 条件式 ; then 処理 fi
if 条件式 ; then 処理1 else 処理2 fi
if 条件式1 ; then 処理1 elif 条件式2 ; then 処理2 else 処理3 fi
「testコマンド」は「真か偽か」だけを返すコマンドです
条件式につかいます
メッセージ出力は行いません(echo $?の結果が「0」なら真「1」なら偽になります)
「testコマンド」のオプション
- 数値を比較
-eq
: 等しい(=)-ne
: 等しくない(!=)
a-ge
b: a が b 以上(≧)
a-le
b : a が b 以下(≦)- a
-gt
b : a が b より大きい(>)
a-lt
b : a が b 未満(<)
- 文字列の比較
=
: 左辺と右辺が等しい!=
:左辺と右辺が等しくない
-n 文字列 : 文字列の長さが0より大きい
-z 文字列 : 文字列の長さが0- 例 “abc” = “abc”
- ファイルのタイムスタンプを比較
-nt
: 左辺が右辺より新い-ot
: 左辺が右辺より古い
- ファイルやディレクトリ
-f '名前'
: ファイル-d '名前'
: ディレクトリ-L '名前'
: シンボリックリンク-r '名前'
: 読み取り可能ファイル-w '名前'
: 書き込み可能ファイル-x '名前'
: 実行権限があれば-e '名前'
: ファイル(ディレクトリ)が存在する-s '名前'
: サイズが 0 より大きい
- 論理演算
- 条件式1
-a
条件式2 : AND(かつ)
条件式1-o
条件式2 : OR(または)!条件式
: 条件式が偽であれば真
「testコマンド」は []
でもかけます(略式)
*「[ の直後」と「 ] の直前」に必ず半角スペースが必要です
「test 1 -eq 1
」は「[ 1 -eq 1 ]
」
「case文」は値とパターンの照合を行い一致したパターンに対応する処理を実行します
上から順に照合して、最初に一致したパターンの処理を行うと終了します
一致しなければ、処理は実行されません
case 値 in パターン1 ) 処理1 ;; パターン2 ) 処理2 ;; … パターンn ) 処理n ;; esac
ループ処理
「for文」は「繰り返し処理の対象(リスト)」が明確なときにつかいます
for 変数 in 値のリスト do 変数を処理する done #コマンドの実行結果をリストにする for 変数 in `コマンド` do 変数を処理する done
「while文」は「始めに指定された条件式」が「真」のときにのみループ処理を継続します
*「until文」は「真」になるまで、繰り返します
「break」は、ループを途中で終了
「continue」は、ループをスキップ
# testコマンドで判定 while [ 条件式 ] do … done # ファイルの中身を1行ずつ読み込む while read 変数名 do ... done <test.txt
*ちなみにwhile :
で無限ループに入ります
forやwhileの条件式で(())「二重丸括弧」がつかえます
*(())はC言語スタイルの条件を書くときにつかいます
for (( i=0; i<3; i++ )); do echo $i; done i=0; while (( $i <= 2 )); do echo $i; ((i++)); done
*例えば、1から100までの数字でfor i in seq 1 100
ともかけます
シェルスクリプトで「FizzBuzz」を書いてみる
#!/bin/bash
# while文で
i=1
while (( $i <= 100 ));
do
if [ $(( i % 3 )) -eq 0 ] && [ $(( i % 5 )) -eq 0 ];
then
echo $i FizzBuzz
elif [ $(( i % 3 )) -eq 0 ];
then
echo $i Fizz
elif [ $(( i % 5 )) -eq 0 ];
then
echo $i Buzz
else
echo $i
fi
i=$(( i + 1 ))
done
# 引数でループ回数をわたし・for文・15の倍数は使わず
for (( i=1; i<=$1; i++ ));
do
str="";
if [ $(( i % 3 )) -eq 0 ];
then
str="Fizz"
fi
if [ $(( i % 5 )) -eq 0 ];
then
str+="Buzz"
fi
echo "$i:$str"
done
select文
「select文」をつかうと、選択メニューが簡単に実装できます
select 変数 in リスト do 選んだ変数の処理 done
メニューとインデックスを表示してループ処理に入ります
インデックスを選択します
ループは「break」で抜けます
if [ループを抜ける条件]; then
break
fi
select command in "list" "delete" "rename" "exit"
do
case $command in
"list" )
ls;;
"delete")
ls
read -p "削除したいファイル名 " file_name
if [ -f $file_name ];
then
rm $file_name
fi;;
"rename")
ls
read -p "ファイル名" file_name
read -p "変更したいファイル名 " new_file_name
if [ -f $file_name ];
then
mv $file_name $new_file_name
fi;;
"exit")
break;;
esac
done
*「select」を使用するときに内部で「$REPLY」という変数がつくられ、選択された値が代入されます
関数をつかう
function 関数名() { 処理 return 値 }
「function」は省略可
*関数の呼び出しに「( )」は不要
関数名 引数リスト
「return」について
シェルスクリプトの関数には「戻り値」の概念がなく、標準出力で結果を返します!!
引数の値は、「0 」か「 1~255 」の正整です
「return」が省略されたときは、関数内で最後に実行されたコマンドの終了ステータスになります
戻り値をつかいたいときは、標準出力に戻り値を出力(echo “戻り値”)し、コマンドの結果を文字列として取得します
(下記は、コマンドの実行結果を変数に格納しています)
func() { echo "戻り値" } # コマンドの実行結果を変数に格納 rtn=`func` echo "戻り値:${rtn}"
引数について
引数は関数内では 「$1… 」で各引数を参照できます(シェルスクリプトと同様)
ローカル変数について
シェルスクリプトでは関数内の変数はグローバル変数です
ローカル変数としたい変数の前に「 local
」 をつけます
「readonly」について
「readonly」指定した変数や関数に対する代入や「unset(削除)」ができなくなります
readonly var # 変数 readonly -a arr # 配列は-aオプション readonly -f func # 関数は-fオプション
「declareコマンド」は、オプションで変数に属性を付与して、変数を宣言するコマンドです
*declareコマンドを使用すると、オプションがなければローカル変数として定義されます
declare [オプション] [変数名]=[値]
オプション | 内容 |
-g | 関数内でグローバル変数として定義 |
-l | 小文字の文字列として定義 |
-x | 環境変数として定義 |
-i | 整数として定義 |
-a | 配列を定義 |
-A | 連想配列を定義 |
シェルスクリプトで「フェボナッチ数」を求めてみる
「0, 1 ,1 ,2, 3, 5 ,8 ,13, 21, 34, 55,89,144 ….(1つ前と2つ前の数を足し合わせた数)」
#!/bin/bash
function fib {
x=$1
if [ $x -eq 0 ]; then
echo 0
elif [ $x -eq 1 ]; then
echo 1
else
x1=`fib $((x-1))`
x2=`fib $((x-2))`
echo $((x1+x2))
fi
}
# 引数の数番目のフィボナッチ数を表示する
for (( i=1; i<=$1; i++ ));
do
if [ $1 -eq $i ]; then
fib "$i"
fi
done
上の式では、毎回計算する(自分を呼び出す)ので数が大きくなるとすごく時間かかります
計算済数は配列に格納して(メモして)再利用します
*20桁未満w
#!/bin/bash
memo=(
[0]=0
[1]=1
[2]=1
)
for (( i=1; i<=$1; i++ ));
do
if [ $i -gt 2 ]; then
f1=${memo[$((i-1))]}
f2=${memo[$((i-2))]}
res=$((f1+f2))
memo[$i]=$res
fi
if [ $i -eq $1 ]; then
echo "$res"
fi
done
デバック
bash -x シェルスクリプト
「-x」オプション : 実行されたコマンドラインが出力されます(変数の値が確認できます)
「+」が付いているコマンドは「シェルスクリプト内」で実行されたコマンド
「++」は 「``
内」で実行されたコマンド
*「-v 」オプション : 実行するコマンドだけを表示します
部分的なデバック(シェルスクリプトに追記)
実行すると「set -x」 から 「set +x」 までの処理内容が出力されます
# デバッグを開始する set -x # デバッグを終了する set +x
カッコ早見表w
カッコの種類 | 役割 |
[] | 条件式 testコマンド等価のコマンド *「[ の直後」と「 ] の直前」に必ず半角スペースが必要です |
(()) | forやwhileの条件をC言語スタイルで書くとき |
$() | `` と同じで、コマンドの実行結果を文字列として展開 |
$(()) | 四則演算(計算)を実行して、結果を文字列に展開する 「$(expr ….)」と同じ *変数をつかうときは、変数の前の$は不要 |
${} | 変数を埋め込みとき echo “${hoge}hoge” 配列の表示 echo ${配列名[0]} |
余談「/bin/bash」がbashの本体のファイルですが、本来「/binはrootユーザのみが操作できるコマンドを置く場所」なので気になり調べると、「/bin」は「/usr/bin」のシンボリックリンクになっていて「/bin/bash」は実際には「/usr/bin/bash」が起動します(今のLinuxファイル構造的では2つを分ける必要がないそうですw)
*ls -l /bin
を実行すると「/bin -> usr/bin」と表示されます