home ホーム search 検索 -  login ログイン  | reload edit datainfo version cmd icon diff delete  | help ヘルプ

技術/shell/bashシェルスクリプトまとめメモ

技術/shell/bashシェルスクリプトまとめメモ

技術 / shell / bashシェルスクリプトまとめメモ
id: 349 所有者: msakamoto-sf    作成日: 2003-04-17 11:50:41
カテゴリ: Linux UNIX シェルスクリプト 

bashでのシェルスクリプトの情報源:

"PS1"等のプロンプトに使えるエスケープシーケンスも、上記manページ中に解説があります。

他、/etc/rc.d/ 以下の各種サービス起動スクリプトが参考になります。

以下は実際にシェルスクリプトを書いていた時のTipsです。



"&&" と "||" と "exec" の使い分け

・"&&"の例 : /foo/bar が存在すれば、$HOME/bin/baz を実行。

[ -f /foo/bar ] && $HOME/bin/baz

・"||"の例 : /foo/bar が存在 ''しなければ''、$HOME/bin/baz を実行。

[ -f /hoge/bohe ] || $HOME/bin/uhyou

多くのプログラミング言語もそうですが、or演算の場合、先にtrue評価の式があると、後ろの式は評価されなくなります。bashの "&&", "||" でも同様の動きになります。

・execの注意点 : execシェルコマンドはプロセスを置き換えてしまいます。つまりexecが実行されたらそれ以降のシェルスクリプトは実行されません(=復帰しません)。各種スクリプトで "&&", "||" と共に exec コマンドも頻出しますが、この点を読み違え無いよう注意が必要です。

ワイルドカード(*)の注意点

便利なワイルドカード、*ですが、使用上の注意点もあります。

たとえば、rhostsファイルのあるディレクトリで

$ find /etc -name r*

として、「rで始まるファイルを/etcから探そう」としても、r* が rhosts に展開されてしまい、

$ find /etc -name rhosts

が実行されてしまいます。

これを避けるには、メタ文字展開の抑制を使います。

$ find /etc -name "r*"
  • シングルクォテーション「'」で囲むと、「!」以外のメタ文字を展開しません。
  • ダブルクォテーション「"」で囲むと、「!, $, `」以外のメタ文字を展開しません。
  • \(バックスラッシュ)だと、この直後の一文字を展開しません。

メタ文字とは関係が薄いですが、コマンド履歴を呼び出す "!!", "!N" をバッククォートで囲むと、中のコマンドが実行された結果に展開されます。

trap組み込みコマンドによるシグナルハンドリング

trap 組み込みコマンドを使うと、シェルスクリプトでシグナルハンドラを使うことが出来ます。

trap コマンド シグナル名(or 番号)

シグナル名 or 番号は signal.h 定義のものになります。"kill -l"で調べることができます。

コマンドの部分は、シェルの内部コマンド、外部コマンドの両方とも可。
複数のコマンドを指定するには「;」で区切り、コマンド全体を""で囲みます。

特定のシグナルを無視するには、コマンドを空文字列にします。

trap "" シグナル番号

特定のシグナルを初期設定に戻すには、コマンドを省略します。

trap シグナル番号

whileループと組み合わせたサンプル :

#!/bin/sh
echo "PID=$$"
while true
do
        trap "echo loop broken...; break" 1
        trap "echo loop continues...; continue" 2
        date
        sleep 3
done
echo "Good Bye."

実行結果:

$ ./test.sh 
PID=1437
2003年  4月 18日 金曜日 00:57:18 JST
# 別ターミナルより "kill -2 1437"
loop continues...
2003年  4月 18日 金曜日 00:57:27 JST
# 別ターミナルより "kill -1 1437"
loop broken...
Good Bye.

evalでshiftによる引数廃棄を回避してみる。

配列を頭から処理する shift コマンドは、特にコマンドライン引数の処理で良く使われます。
たまに問題になるのが、shiftコマンドだと一旦shiftされた引数が廃棄されてしまう点です。

これをevalコマンドを用いて回避するサンプルコードを作ってみました。

#!/bin/bash
num=1
while [ $num -le $# ] ; do
eval echo "Argument $num is " \$\{$num\}
num=`expr $num + 1`
done

evalは変数を展開しますので、

\$\{$num\}

の部分の

$num

がwhileループで回るnumに展開されます。つまり、例えば最初のループでは

echo "Argument 1 is " ${1}

が評価(つまり実行)されることになります。

実行例 :

$ sh foo.sh a b c d
Argument 1 is a
Argument 2 is b
Argument 3 is c
Argument 4 is d

bashのバージョン2以降は配列を扱えます

a[0]=a
a[1]=b
a[2]=c

或いは

a=(a b c d)
files=(`ls`)

参照するには ...

echo ${a[0]} 
echo ${files[3]}
echo ${a[@]} # 全参照

コロンの変則的な使い方。

${name:+value} # name変数が空白でなければ、valueが値となる。
${name:-value} # name変数が空白であれば、valueが値となる。
${name:=value} # name変数が空白であれば、name=valueとなる。
${name:?value} # name変数が空白であれば、valueを標準エラー出力に流し、
                 スクリプトの実行を中止する。
${name:start} # nameのstartバイト目から最後まで出力。
${name:start:length} # nameのstartバイト目からlength文字分出力

case文の条件式部分のバリエーション

case $x in
    y|m)    flag="*" ;;
    n)      flag=" " ;;
esac

これだとy or mの時、が簡単に表現できる。

履歴参照 & 履歴からコマンドラインの引数を取ってくる

直前のコマンド実行

!!

"ls"で始まる直近のコマンド実行

!ls

直前に実行したコマンドライン中の"foo"を"bar"に置換して実行

!:s/foo/bar

直前のコマンドの最初の引数

vim foo.txt
mv !^

直前のコマンドの最後の引数

hoge.sh a.txt b.txt c.txt
rm !$

直前のコマンドの引数全て

hoge.sh a.txt b.txt c.txt
rm !*

参考:

  • bash/zshのコマンドライン履歴機能。直前のコマンド、直前の引数。 - ミームの死骸を待ちながら
  • bash(1) : 「イベント指示子 (Event Designator)」、「単語指示子 (Word Designators)」


プレーンテキスト形式でダウンロード
現在のバージョン : 4
更新者: msakamoto-sf
更新日: 2013-01-28 08:09:37
md5:370f7d852b2e8f4783b488be6e7596e9
sha1:e6930611b0d29317bd54e0ea7f9333080246a3ad
コメント
コメントを投稿するにはログインして下さい。