ラベル Bash の投稿を表示しています。 すべての投稿を表示
ラベル Bash の投稿を表示しています。 すべての投稿を表示

2015-08-27

シェルスクリプトで変数のデフォルト値を使う

${var:-foo}変数varが未定義の時fooを返す
${var:=foo}変数varが未定義の時fooを代入する。
${var:+foo}変数varに値がセットされているときfooを返す
${var:?puyo}変数varが未定義の時"puyo"を出力しexit 1する

な感じで使えます(ノ゚⊿゚)ノ

2015-08-26

cronから起動されたスクリプトの多重起動チェック

多重起動チェックについてググってみると次のような例が多く見つかりました

[[ $$ != `pgrep -fo "$0"`  ]] echo "$0 is already running" && exit 2

これは、自身と同じプロセス名を検索して、

そのもっとも古いプロセスIDが自身のプロセスIDと一致していればおーけー

という処理になります。

ただ、これは直接スクリプトを実行した場合にのみ有効で

cronなどから子プロセスそしてスクリプトを実行した場合は

$$は子プロセスとして起動されたスクリプトのプロセスID

pgrep -fo "$0"で引っかかってくるのが起動元の親プロセスのIDとなり

一致しないので、多重起動として扱われてしまいました(´・ω・`)

これに対応するため、親プロセスIDが格納される$PPIDとの比較も追加して次のようにしてみました

[[ $$ != `pgrep -fo "$0"`  ]] && [[ $PPID != `pgrep -fo "$0"`  ]] && echo "$0 is already running" && exit 2

これで、直接起動した場合も、cronなどから子プロセスとして起動した場合も多重起動チェックできますヾ(*・ω・)シ

シェルスクリプトで変数に格納された文字列から部分文字列を抽出する

str=abcdefg

echo ${str:0:2}  # ab
echo ${str:2:2}  # cd

な感じ(ノ゚⊿゚)ノ

2014-09-29

bashで排他制御を実現する

まずはテストファイルを作成
$ seq 10 > /tmp/test
$ cat /tmp/test
1
2
3
4
5
6
7
8
9
10

ここから先頭行を取り出して/tmp/resultに追記し、先頭行を削除するという処理を10回実施してみる

■ダメな例
※/tmp/testから10行削除は成功しているが、抽出して/tmp/resultに追記した値が削除した行と一致していない
$ for i in `seq 10`
do
  head -1 /tmp/test >> /tmp/result;sed -i '1d' /tmp/test &
done
[1] 28066
[2] 28068
[1]-  終了      sed -i '1d' /tmp/test
[3] 28070
[2]-  終了      sed -i '1d' /tmp/test
[4] 28072
[3]-  終了      sed -i '1d' /tmp/test
[4]+  終了      sed -i '1d' /tmp/test
[1] 28074
[2] 28076
[1]-  終了      sed -i '1d' /tmp/test
[2]+  終了      sed -i '1d' /tmp/test
[1] 28078
[2] 28080
[1]-  終了      sed -i '1d' /tmp/test
[3] 28082
[2]-  終了      sed -i '1d' /tmp/test
[4] 28084
[3]-  終了      sed -i '1d' /tmp/test
[4]+  終了      sed -i '1d' /tmp/test
$ cat /tmp/test
$ cat /tmp/result
1
1
2
4
4
5
7
7
9
9

■良い例
flockを利用する
/tmp/testから削除した行と、/tmp/resultに追記した値が一致している
$ touch /tmp/test.lock
$ for i in `seq 10`
> do
>   flock -x /tmp/test.lock -c "head -1 /tmp/test >> /tmp/result;sed -i '1d' /tmp/test" &
> done
[1] 28111
[1]+  終了      sed -i '1d' /tmp/test
[1] 28114
[1]+  終了      sed -i '1d' /tmp/test
[1] 28117
[1]+  終了      sed -i '1d' /tmp/test
[1] 28120
[1]+  終了      sed -i '1d' /tmp/test
[1] 28123
[1]+  終了      sed -i '1d' /tmp/test
[1] 28126
[1]+  終了      sed -i '1d' /tmp/test
[1] 28129
[1]+  終了      sed -i '1d' /tmp/test
[1] 28132
[1]+  終了      sed -i '1d' /tmp/test
[1] 28135
[1]+  終了      sed -i '1d' /tmp/test
[1] 28138
[1]+  終了      sed -i '1d' /tmp/test
$ cat /tmp/test
$ cat /tmp/result
1
2
3
4
5
6
7
8
9
10

2013-01-07

sedで&(アンパサンド)に置換する

sedコマンドで&に置換しようとすると、&はヒットした文字列を意味してしまうので意図する通りに置換されてくれません
$ hoge="a&b"
$ echo "xyz" | sed "s/y/$hoge/"
xaybz
な感じ。 なので、bashに組み込まれている置換コマンドを併用してやるとうまくいきました
$ echo "xyz" | sed "s/y/${hoge/&/\&}/"
xa&bz
ほらねヾ(*・ω・)シ

2012-11-02

Bashでアルファベット順にn文字ずらした文字列を得る

用途があるかどうかわからないけどメモ。

例えば
1文字ずらしだとhello→ifmmp
2文字ずらしだとhello→jgnnq
みたいな感じ
1文字ずらしなら
echo "hello" | tr '[a-z]' '[b-za-b]'
2文字ずらしなら
echo "hello" | tr '[a-z]' '[c-za-c]'
てな風にすれば得られる