LoginSignup
42
49

More than 5 years have passed since last update.

シェルスクリプトでハマったところ

Last updated at Posted at 2016-02-21

シェルスクリプトではまった点についてまとめる。

■ 検索

● locateとfindの違い

ファイル名が分かっている場合はインデックスを参照するlocateの方が高速。

# インデックスの更新
sudo updatedb
locate ファイル名

■ 計算

● 実数の計算は"bc"コマンドを使う必要がある。

scalceで少数点以下の桁数を調整。

# echo "scale=2; 10 / 3" | bc
3.33
# echo "scale=3; 10 / 3" | bc
3.333
# echo "scale=4; 10 / 3" | bc
3.3333

# echo "scale=4; 0.1 / 10" | bc
.0100

■ 条件分岐

● 文字列比較には=, 数値比較は"-eq"

● if文における [[]] と []の違いについて

■ 関数

● 関数の戻り値に文字列を指定できない

return コマンドの引数に指定できる値は、1~255 の正の整数のみ
return コマンドの引数に指定できる値は、0~255 の整数のみ

● ローカル変数を使用するには、localを指定する必要がある

一般的なプログラミング言語と異なり、使用する変数はグローバル変数になる。
ローカル変数にするにはlocalを使用する必要がある。

func() {
  local x="local"
}

■ shellのオプションを設定するにはsetコマンド

オプション 内容
x コマンドと引数の展開処理(デバッグ)内容を標準エラー出力
v コマンドの実行行を標準エラー出力
n コマンドを実行せず,構文エラーだけを確認する
u 未定義の変数を参照するとエラー・メッセージを表示
e コマンドが0以外のステータスで終了した場合,一部の場合を除いて即座に終了する
f パス名のワイルドカードによる展開(*や?)を無効にする
o ignoreof CTRLキーを押しながらDキーを押しても,シェルを終了しないように設定する。exitコマンドは利用できる
# xオプションを有効化
set -x

echo "test command"

# +で無効化。
set +x 

■ 特殊記号を無効にする

● 関数に特殊文字を渡す

# パス名のワイルドカードによる展開(*や?)を無効にする
set -f
function "* * * argv"
set +f

● grepで特殊記号を無効

grep -Fを使う

grep -Fとは
-F ⇒ --fixed-strings
パターンではなく固定文字列での検索を行う。

http://togattti.hateblo.jp/entry/2014/01/19/001418

■ プロセスが強制停止しても、確実に処理を行いたい場合はtrapコマンド

● trapコマンド

実行中のプロセスに対するシグナルを検知し、指定された処理を返すコマンド

シグナル とは

実行中のプロセスに対して、プロセス停止などのイベントを通知するために>送出される信号

シグナル番号 シグナル名 通知内容
1 HUP プロセスに再起動を通知する。
2 INT プロセスに割り込みを通知する。(Ctrl+c)
3 QUIT プロセスに終了を通知する。(coreを作成する)
9 KILL プロセスに強制終了を通知する。
15 TERM プロセスに終了を通知する。(デフォルト)
18 CONT プロセスに再開を通知する。
19 STOP プロセスに中断を通知する。
20 TSTP プロセスにサスペンドを通知する。(Ctrl+Z)
# -l シグナル一覧を表示する
# -p 指定された処理を確認できる
trap -l
trap -p

# プロセスの終了シグナル(0)を受け取った際に、コマンドを実行する
# trap "コマンド" [シグナル or  シグナル名]
trap "
    echo '`basename $0` end.'
    echo 'status is $?'
" 0

■ ファイル名の取得

#!/bin/bash

# ファイルのフルパスを取得
# シンボリックリンクの場合は実態の取得
# $0 : 自身のファイルパス
echo $(readlink -f $0)

# -f : ファイルが存在しなくてもフルパスを返す
# -e : ファイルが存在しないときは返り値なし
echo $(readlink -f not_found_file.txt)
echo $(readlink -e not_found_filei.txt)

# ディレクトリ名の取得
echo `dirname $(readlink -f $0)`

# ファイル名の取得
echo `basename $(readlink -f $0)`

■ 2重起動防止

if [ $$ != `pgrep -fo $0`  ]; then
    echo "[`date '+%Y/%m/%d %T'`] warning already running."
    exit 1
fi
処理 意味
\$0 スクリプト名
$$ このシェルスクリプトのプロセスID
pgrep プロセス名を指定してプロセスIDを表示
pgrep -f パターンにマッチしたプロセスを全て表示
pgrep -o マッチしたプロセスから最古のものを表示


■ ネットワークデバイスのデバイス名が変更される

ネットワークデバイスのデバイス名がeth0⇒eth1がMACアドレスの変更などにより、変更されることがある。

この場合、設定ファイルのデバイス名を書き換えることで、もとに戻せる。

cd /etc/udev/rules.d
view 70-persistent-net.rules
# NAMEをeth0に変更する
SUBSYSTEM=="net", ACTION=="add", DRIVERS=="?*", ATTR{dev_id}=="0x0", ATTR{type}=="1", KERNEL=="eth*", NAME="eth0"

http://blog.livedoor.jp/itukano/archives/51865711.html
http://d.hatena.ne.jp/ktat/20090716/1247745069

■ 起動時にRamdiskをマウント

■ 変数を2重展開する際はevalコマンドを使う

# 変数名を代入する
$ color="red"
$ VALUE_NAME="color"

# 変数名を使って、変数の値を出力
$ eval echo '$'"${VALUE_NAME}"
red

■ whileの外で変数を使用すると空文字になるケースがある

パイプを使うとパイプ先の処理は、別プロセス(別シェル)になるため、cat file | while ~のようなループ処理をすると、
whileが別シェルとなるので、while文中に定義した変数は、whileの外で使うと未定義のため、空文字になる。

cat "${file}" | while read line;
do
    value="${line}";
done
echo "${value}"

■ 参考

42
49
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
42
49