最近覚えたシェルスクリプトの小ネタ
シェルスクリプト神から教えていただいた。忘れないように書いとく
(追記)聞いて、自分の記憶した内容をそのまま書いちゃったので、ちゃんとマニュアル通りか確認してなかったので反省
下の例だと
番外編:やたら
testコマンドを使うとフォークしてしまって大量に叩くとパフォーマンス悪いとのこと。
$ man bash
目次
●xargsでfunctionを叩く ●連想配列もどき ●変数間接参照 ●なんでもかんでもawkで整形しない ●文字列の末尾から数えて○文字目を△文字取り出す ●番外編:やたらif [ ]; then
を使わない
※Markdownで目次の書き方がわからんかった
xargsでfunctionを叩く
find xxxx | xargs cp xxxx
ってかけば良さそうでイマイチだけど、もっと複雑な処理やらせたいときに。
●前はこう書いてた
#!/bin/bash forxin `find /var/www -name xxx` do cmd="cp -v /hoge/fuga/xxx $x" [[ `md5sum $x | awk '{print $1}'` != "xxxxxxxxxxxxxxxxxxxxxxx" ]] && eval $cmd | : done●xargsで5多重で同じことやらせる
#!/bin/bash function sample() { cmd="cp -v /hoge/fuga/xxx $1" [[ `md5sum $1 | awk '{print $1}'` != "xxxxxxxxxxxxxxxxxxxxxxx" ]] && eval $cmd | : } # これしたらxargsから呼べることをしらなかった export -f sample find /var/www -name xxx | xargs -P5 -I{} bash -c "sample {}"
連想配列もどき
# 連想配列もどきのHを定義 declare -AHH["a"]="682f7xxxxxxxxxxxxxxxxxxx0"H["b"]="7808axxxxxxxxxxxxxxxxxxx2"H["c"]="c6ba1xxxxxxxxxxxxxxxxxxx6"H["d"]="64186xxxxxxxxxxxxxxxxxxxb"H["e"]="50d1dxxxxxxxxxxxxxxxxxxxc" forxin a b c d e do # とりだす echo ${H["$x"]} doneちなみに、 ●こっちは配列見える
declare -AHH["a"]="682f7xxxxxxxxxxxxxxxxxxx0"H["b"]="7808axxxxxxxxxxxxxxxxxxx2"H["c"]="c6ba1xxxxxxxxxxxxxxxxxxx6"H["d"]="64186xxxxxxxxxxxxxxxxxxxb"H["e"]="50d1dxxxxxxxxxxxxxxxxxxxc" function sample(){ # 682f7xxxxxxxxxxxxxxxxxxx0 echo ${H["a"]} } sample●こっちは配列見えない
#!/bin/bash declare -AHH["a"]="682f7xxxxxxxxxxxxxxxxxxx0"H["b"]="7808axxxxxxxxxxxxxxxxxxx2"H["c"]="c6ba1xxxxxxxxxxxxxxxxxxx6"H["d"]="64186xxxxxxxxxxxxxxxxxxxb"H["e"]="50d1dxxxxxxxxxxxxxxxxxxxc" function sample(){ # 682f7xxxxxxxxxxxxxxxxxxx0 echo ${H["a"]} echo "hoge" } # ここで配列はexportされないらしいけど、あんまり詳しく調べてない。当たり前の動き? export -f sample find ~/test -type f | xargs bash -c "sample"
変数間接参照
#!/bin/bash var1="xxxxxxxxxxxxxxxx" var2="yyyyyyyyyyyyyyyy" var3="zzzzzzzzzzzzzzzz" foriin `seq 1 3` do # 変数を使って作る変数名は一度変数に入れなきゃだめ tmp="var${i}" echo ${!tmp} done
なんでもかんでもawkで整形しない
/home/hoge/fuga/piyo/php5.2.cgi
のようなパスから、末尾の php5.2.cgi
のみ抽出し、かつその値を利用して色々処理したい時に、つい以下のようなことを書いてた。
[root@hoge ~]# cat test.sh #!/bin/bash forxin `find ~/home/users/php-bin/ -path "*/.php-bin/php*.cgi"` do echo $x | awk -F/ '{print $10}' doneこのくらいのことをawk出してるとコストが高いので、bashの変数操作を使って以下の様に書く
[root@hoge ~]# cat test2.sh #!/bin/bash forxin `find ~/home/users/php-bin/ -path "*/.php-bin/php*.cgi"` do echo ${x##/*/} doneすると
[root@hoge ~]# time ./test.sh ・・・ real 0m8.316s user 0m2.367s sys 0m7.828s [root@hoge ~]# time ./test2.sh ・・・ real 0m0.763s user 0m0.357s sys 0m0.394s圧倒的に早い!!! 捕捉 この例だと
find ~/home/users/php-bin/ -path "*/.php-bin/php*.cgi" | awk -F/ '{print $10}'でいいけど、今回のこれは、①findしたパス②awkで整形した値両方を使用して、いろいろ処理する必要があって、forを利用してた
文字列の末尾から数えて○文字目を△文字取り出す
以下は乱暴な例ですが、5.x
の x
の値に応じて処理したい要件があった。
先頭の文字はファイルによってバラバラの長さのため、cutコマンドでは取得できないため、﹁末尾から何文字目﹂という指定をしたかった
[user ~/work/test]$ ll total 0 -rw-r--r-- 1 user staff 0B 6 28 00:49 hogehogeho_ver5.2.sh -rw-r--r-- 1 user staff 0B 6 28 00:49 xxxx.yyyy-abcdefghijk_ver5.2.sh -rw-r--r-- 1 user staff 0B 6 28 00:49 xxxxxxxxxxxxxxxxxxxxxxxxxxx_ver5.2.sh -rw-r--r-- 1 user staff 0B 6 28 00:49 yyyyyyyyyyyy-aaaaaaaaaaaaaaaa_ver5.3.sh [user ~/work/test]$ forxin `find . -type f` > do > echo ${x:${#x}-4:1} > done 2 2 2 3
番外編:やたら if [ ]; then
を使わない
[PMAC226S ~/work]$ cat test.sh #!/bin/bash foriin `seq 1 1000000` do if [ "$a" = "hoge" ]; then echo "hoge" else echo "fuga" fi doneと
[PMAC226S ~/work]$ cat test2.sh #!/bin/bash foriin `seq 1 1000000` do [[ "$a" = "hoge" ]] && echo "hoge" || echo "fuga" doneがあった時、後者の方が結構はやい
[PMAC226S ~/work]$ time ./test.sh ・・・ real 0m30.164s user 0m20.777s sys 0m2.917s [PMAC226S ~/work]$ time ./test2.sh ・・・ real 0m25.246s user 0m17.777s sys 0m1.812s