(Linux) シェルスクリプトの使い方メモ

戻る一つ前のメニューに戻る

目次

コマンドライン編集のキーアサイン

カーソル移動

右へ : →/Ctrl+f(1文字) Esc+f(1ワード) Ctrl+a(行頭)
左へ : ←/Ctrl+b(1文字) Esc+b(1ワード) Ctrl+e(行末)

削除

その位置1文字 : Del/Ctrl+d
左へ1文字 : Bs/Ctrl+h
行頭まで全て : Ctrl+u
行末まで全て : Ctrl+k

コマンドライン検索(インクリメンタル)

検索開始(現在位置から過去へ) : Ctrl+r
同一条件で再検索 : Ctrl+r
最古のコマンドへ : Esc+<
最新のコマンドへ : Esc+>

直前のコマンド再実行

!!

補完

コマンド名・ファイル名補完 : Tab
コマンド名強制補完 : Esc+!
ファイル名強制補完 : Esc+/
ユーザ名補完 : Esc+~
変数名補完 : Tab(変数を$で書きはじめたとき) Esc+$(変数を$で書きはじめないとき)

過去に実行したコマンドを表示する

history

ジョブ制御:フォアグラウンド、バッググラウンド

ジョブ一覧の表示

jobs

ジョブを一時停止

Ctrl + Z

一時停止中のジョブを、フォアグラウンドで再開

fg [ジョブ番号]

一時停止中のジョブを、バックグラウンドで再開(コマンド実行時に & を付けるのと等価)

bg [ジョブ番号]

サブシェルで実行されるかどうか

現在のシェル内で実行される例

source ./test.sh

サブシェルが起動され、その中で実行される例

sh ./test.sh
./test.sh

条件実行

終了ステータスによる判断

command1の終了ステータス0(真)のときに実行 : command1 && command2
command1の終了ステータス0以外(偽)のときに実行 : command1 || command2

ファイル名のマッチング

検索して条件を満たしたファイル名すべてに展開される

0文字以上の任意の文字 : *
任意の1文字 : ?
パターン内の任意の1文字 : [pattern] (例 [0-9], [0-9a-z])

指定した文字列に展開される

{str1,str2,..} : 例 img{001,002,003}.jpg

空白(スペース)文字を含んだファイルの処理

forで切り分けるときの区切り文字を、「空白文字or改行」から「改行のみ」に変更する例

IFS_BACKUP=$IFS
IFS=$'\n'
for fullpath in $*
do
   echo $fullpath
   file $fullpath
done
IFS=$IFS_BACKUP

上の例は、スクリプトファイルの引数としてファイル名を受け取る場合、直接スクリプト内に記述する場合は次のようにすればよい。

for fullpath in `find . -type f -print`

特殊文字の無効化

ファイル名に * や ? を使ったものなどを扱うとき

/ : 直後の1文字の特殊性を無効化
'...' : 囲まれた範囲内の特殊性を無効化
"..." : 囲まれた範囲内の特殊性を無効化(ただし、変数の$は有効)

リダイレクト

> または 1> : 標準出力 (例:command > output.txt)
2> : 標準エラー出力

組み合わせて用いる例として

command 1> output.txt 2> error.txt : それぞれ別のファイルに保存する
command 1> output.txt 2>&1 : エラー出力も同一ファイルに保存する

標準入力(キーボード)で入力した内容を、ファイルに保存する例

cat > output.txt

出力を切り捨てる例

command > /dev/null 2>&1 : すべての出力を切り捨てる
command > output.txt 2> /dev/null : エラー出力のみ切り捨てる

変数

シェル変数の定義、削除

val=str : 変数valに値を代入
export val : 変数valをサブシェルでも利用できるようにエクスポート
export val=str
unset val : 変数valの定義を削除する
$val : 変数を参照 (例:echo $val)
${val} : 変数を参照

変数一覧の表示

set

シェルの引数

$1, $2, ... : シェル起動時に渡された引数
$* : 全ての引数を結合した文字列。
      $* = $1 + " " + $2 + " " + $3 + ...
"$*" : 全ての引数を結合した文字列。結合時に$IFSの文字を挟む(未定義時は空白文字)
      $* = $1 + "$IFS" + $2 + "$IFS" + $3 + ...
"$@" : 全ての引数を結合した文字列
$# : 引数の総数(数値)。1, ...
$0 : シェルスクリプト名

引数のシフト

shift n : n個ずらす。結果として、$#で返される総数も減る

shift 1 : $1を切り捨て、$2を$1に、$3を$2に、...

関数の引数

function func()
{
  echo $1
  echo $2
}

func one two

シェル引数でなく、関数呼び出し時の引数が参照される

シェルの引数を解析

for $str in "$@"; do
  echo $str
done

上記の実行結果

$ sh test.sh "param one" two
 param one
 two

$@を"$@"のように囲った場合は、引数で"..."で囲まれた部分は一つの文字列と認識できる

シェルプロセスの実行環境を取得

$? : 直前のコマンドの終了ステータス(0:成功、1~125:失敗、126:実行不可、127:コマンド不存在)
$$ : シェルのPID

変数の値に応じた自動補完等

${val:-str} : valが定義されていなければstrを返す、定義されていればその値を返す
${val:=str} : valが定義されていなければstrを定義して返す、定義されていればその値を返す
${val:n} : valの先頭からn文字スキップして、それ以降を返す
            val="one two"
            echo ${val:2}  → "e two"を表示
${val:n,m} : valの先頭からn文字スキップして、それ以降m文字を返す
${@:n,m} : シェル引数を扱う。文字ではなく、引数毎の数えかたとなる
            echo ${@:2,3} → "two three four"

特別に定義されているシェル変数

PATH : コマンド検索パス
PS1 : プライマリシェルのプロンプト(例:PS1=[\u@\h \W]\$)
HOME : ホームディレクトリ
LANG : 言語環境(例:LANG=ja_JP.UTF-8)

変数をセットするスクリプトを作成する場合、「サブシェルで実行されるかどうか」セクションで説明しているように、実行元のシェルに結果を反映させるためには source コマンドで実行する必要がある。

配列

値のセット

val=( str1 str2 str3 )
val=( [1]=str1 [3]=str3 )
val[5]=five

値の参照

${val[n]} : インデックスnの値を参照(例:${val[3]})
${val[*]} : 全て結合(間はスペース文字)して1つの文字列とする
"${val[*]}" : 全て結合(間は$IFSにセットされた文字)して1つの文字列とする
${#val[*]} : 配列の要素数
${#val[n]} : 配列の要素n番の文字列の長さ

コマンド、数式や条件評価

コマンドの実行結果を変数に取り込む

val = $(cmd param1 param2)

例:/dev/sda12の利用可能サイズを変数に格納

val = $(df | grep sda12 | awk '{print $4}')

算術式評価結果を変数に取り込む

val = $((算術式))

val1 = 10
val2 = 5
sum = $((val1 + val2))

フロー制御(if, for, case, while)

if構文

if 条件式
then
  処理を記述
elif 条件式
then
  処理を記述
else
  処理を記述
fi

スクリプトの引数を判定するif文の例

if [ $1 == "-help" -o $1 == "-?" ]
then
  echo "ヘルプ文の表示"
  exit
fi
if [ $# -ne 1 ]
then
  echo "引数は1個です"
  exit
fi

あるプロセス(progA)が存在したら、特定のプログラム(progB)を実行する例 (1行で記述)

[ -n "$(pgrep -f /usr/bin/progA)" ] && /usr/bin/progB

for構文

for val in val1 val2 val3 ...
do
  処理を記述
done
for ((i=0; i>8; i++))
do
  処理を記述
done

連番の付いた空ファイルを作成する例

for ((i=0;i<10;i++)); do echo -n > temp$i.tmp; done

行を分けて書く場合は

for((i=0;i<10;i++))
do
 echo -n > temp$i.tmp
done

select構文

select val in val1 val2 val3 ...
do
  処理を記述
done

Cのselect caseと違い、valにそれぞれの値をセットして順次実行する

case構文

case val in
  val1)
    処理を記述
    ;;
  val2)
    処理を記述
    ;;
  *)
    処理を記述
    ;;
esac

while構文

while 条件式
  処理を記述
done

while test $i -gt 0
  echo $i
  ((i--))
done

until構文

until 条件式
  処理を記述
done

条件式が偽の場合にループする

ループの中断

for, while, until, select を中断する

break

n個のループを抜け出すには

break n

ループのスキップ

continue

testコマンド

条件式を評価し、ステータスコードを返す

test 条件式
test ! 条件式 : 条件式が偽のときに真を返す
test 条件式1 -a 条件式2 : ふたつの条件式が共に真の場合のみ真を返す (AND)
test 条件式1 -o 条件式2 : ふたつの条件式のどちらかが真の場合のみ真を返す (OR)

ファイルの検査

test -a ファイル名 : ファイルが存在する場合に真を返す
test -b ファイル名 : ブロックデバイスの場合に真を返す
test -c ファイル名 : キャラクタデバイスの場合に真を返す
test -d ファイル名 : ディレクトリの場合に真を返す
test -f ファイル名 : 普通のファイルの場合に真を返す
test -h ファイル名 : シンボリックリンクの場合に真を返す
test -r ファイル名 : 読み込み許可ありの場合に真を返す
test -w ファイル名 : 書き込み許可ありの場合に真を返す
test -s ファイル名 : ファイルサイズがゼロ以上の場合に真を返す
test -x ファイル名 : ファイルが存在し実行可能であれば真を返す
test ファイル1 -nt ファイル2 : ファイル1が、2より更新時刻が新しい場合真
test ファイル1 -ot ファイル2 : ファイル1が、2より更新時刻が古い場合真

文字列の検査

test -z str : 文字列の長さがゼロの場合に真を返す
test -n str : 文字列の長さがゼロ以上の場合に真を返す
test str1 = str2 : 「==」ではなく「=」であることに注意
test str1 != str2
test str1 < str2 : 数値比較ではなく、文字列のソーティングで比較する
test str1 > str2

数値の検査

test val1 -eq val2
test val1 -ne val2
test val1 -lt val2 : val1 < val2
test val1 -gt val2 : val1 > val2
test val1 -le val2 : val1 <= val2
test val1 -ge val2 : val1 >= val2

そのほかの条件式評価方法
[ ファイル演算条件式 ]という方法も使える

[ -f ファイル名 ] : test -f ファイル名 と等価

(( 数値演算条件式 ))という方法も使える

((val1 -eq val2)) : test val1 -eq val2 と等価

if構文中でtest構文を利用する例

if test val1 -eq val2
then
  処理
fi

これと等価なのは(構文上、処理は1行だけしか出来ない)

((val1 -eq val2))
処理

また、ファイル演算の場合は

[[-f ファイル名]]
処理

ファイル検索して見つかったファイル(ディレクトリは除外)を処理する例

for i in *; do [ ! -d "$i$ ] && echo "$i"; done
for i in *; do if test ! -d "$i" ;  then echo "$i"; fi; done

あるファイルが存在する場合、それを削除する例

[ -f /var/log/logfile.txt ] && rm /var/log/logfile.txt

スクリプト制御(exit, return)

スクリプトを終了する

exit

また、終了コードを指定する場合は(例:真は0、偽は1~の値をセットする)

exit n

関数を終了する(終了コードが必要な場合は、nを指定する)

return n

ユーザ入力、画面出力(read, printf)

標準入力から読み込む

read val1 val2 ...
read -p "prompt" val

成形して出力する(Cのprintf関数と同じ)

printf "%10s %X\n" str1 val1
戻る一つ前のメニューに戻る