最近覚えたシェルスクリプトの小ネタ
シェルスクリプト神から教えていただいた。忘れないように書いとく
(追記)聞いて、自分の記憶した内容をそのまま書いちゃったので、ちゃんとマニュアル通りか確認してなかったので反省
$ man bash
目次
- xargsでfunctionを叩く
- 連想配列もどき
- 変数間接参照
- なんでもかんでもawkで整形しない
- 文字列の末尾から数えて○文字目を△文字取り出す
- 番外編:やたら
if [ ]; then
を使わない
※Markdownで目次の書き方がわからんかった
xargsでfunctionを叩く
下の例だと find xxxx | xargs cp xxxx
ってかけば良さそうでイマイチだけど、もっと複雑な処理やらせたいときに。
- 前はこう書いてた
#!/bin/bash for x in `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 -A H H["a"]="682f7xxxxxxxxxxxxxxxxxxx0" H["b"]="7808axxxxxxxxxxxxxxxxxxx2" H["c"]="c6ba1xxxxxxxxxxxxxxxxxxx6" H["d"]="64186xxxxxxxxxxxxxxxxxxxb" H["e"]="50d1dxxxxxxxxxxxxxxxxxxxc" for x in a b c d e do # とりだす echo ${H["$x"]} done
ちなみに、
- こっちは配列見える
declare -A H H["a"]="682f7xxxxxxxxxxxxxxxxxxx0" H["b"]="7808axxxxxxxxxxxxxxxxxxx2" H["c"]="c6ba1xxxxxxxxxxxxxxxxxxx6" H["d"]="64186xxxxxxxxxxxxxxxxxxxb" H["e"]="50d1dxxxxxxxxxxxxxxxxxxxc" function sample(){ # 682f7xxxxxxxxxxxxxxxxxxx0 echo ${H["a"]} } sample
- こっちは配列見えない
#!/bin/bash declare -A H H["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" for i in `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 for x in `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 for x in `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]$ for x in `find . -type f` > do > echo ${x:${#x}-4:1} > done 2 2 2 3
番外編:やたら if [ ]; then
を使わない
testコマンドを使うとフォークしてしまって大量に叩くとパフォーマンス悪いとのこと。
[PMAC226S ~/work]$ cat test.sh #!/bin/bash for i in `seq 1 1000000` do if [ "$a" = "hoge" ]; then echo "hoge" else echo "fuga" fi done
と
[PMAC226S ~/work]$ cat test2.sh #!/bin/bash for i in `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
第9回 コンテナ型仮想化の情報交換会@福岡で「Alpine Linux 入門した」という発表をした
人生初しゃべりでした。声が震えてた
内容のレベルは正直低くて、まだまだ勉強不足感がありあり。
だけど、特性を知った上で計測をしつつ、良い使い道を模索できたので、そんなに悪い結果ではなかったと思いたい。
スライド内で使用したDockerfileはGithubに
(追記)サイズの話ばかりしてたけど、小さいってことは余計なものが入ってないから、セキュアなのでした。 公式サイトにも記載あるし。
よく使うGitHubのリポジトリは、ブラウザのカスタム検索設定をしておくと便利
よくあるアレ 設定が面倒くさくて放置してたけど、便利
やりたいこと
ブラウザのアドレスバーから https://git.tahira.com/hoge/fuga
のissue検索を行いたい
通常のフローだと、3ステップ
https://git.tahira.com/hoge/fuga
へアクセス- 左上の検索欄にキーワード入力して検索
- issueタブを選択
設定すると、1ステップ
- ブラウザのアドレスバーから直接ジャンプ
設定方法
GoogleChromeの場合
(1) GoogleChromeの設定画面から 検索エンジンの管理...
を選択
(2) 検索エンジンを追加
より新規追加
- 検索エンジンを追加・・・任意の名前
- キーワード・・・アドレスバーからカスタム検索を実行するためのキーワード(なんでもよい)
- URL・・・通常のフローで検索した際のアドレスバーからコピる。サンプル:
https://git.tahira.com/hoge/fuga/search?q=検索したいキーワード&type=Issues&utf8=%E2%9C%93
これの、q=XXXXXX
をq=%s
に修正して記載
使用方法
(1) アドレスバーに設定したキーワード hogefuga
と入力
(2) スペースを開けると GH:E hogefuga を検索
と表示が切り替わるので続けて検索したいキーワードを入力しEnter
以上!
timestampを見易い形式に変換するAlfredワークフローを作った
Apache拡張モジュール「mod_resource_checker」のソースを眺めてる (途中)
はじめに
- Cのお勉強のいっかんとして取り組んでいます
- なので、誤った情報である可能性があります
- 自分用の覚え書き情報が主なので、役に立たないかもしれません
お題
mod_resource_checker?
Process Resource Logging Module using JSON format into file or piped program.
アクセス毎にApacheプロセスの使用したOSのリソース情報を、JSON形式でログ出力することができます。
[PMAC226S ~/Downloads]$ tail -1 resource.log | jq . { "module": "mod_resource_checker", "date": "Sun Feb 28 22:53:58 2016", "type": "RCheckALL", "unit": null, "location": "/var/www/*/*/web/", "remote_ip": "123.456.789.000", "filename": "/var/www/web/wp/index.php", "scheme": "http", "method": "GET", "hostname": "hoge.com", "server_ip": "192.168.0.111", "uri": "/wp/index.php", "real_server_name": null, "uid": 1234, "size": 418, "content_length": 0, "status": 200, "pid": 16431, "threshold": null, "response_time": 0, "result": { "RCheckUCPU": 0.552367, "RCheckSCPU": 0.00806, "RCheckMEM": 0.644531 } }
mod_resource_checker.c
読んでいきます
1. 末尾のモジュールをApacheへ登録する部分
722 723 #ifdef __APACHE24__ 724 AP_DECLARE_MODULE(resource_checker) = { 725 #else 726 module AP_MODULE_DECLARE_DATA resource_checker_module = { 727 #endif 728 STANDARD20_MODULE_STUFF, (void *)resource_checker_create_dir_config, /* create per-dir config structures */ 729 NULL, /* merge per-dir config structures */ 730 (void *)resource_checker_create_config, /* create per-server config structures */ 731 NULL, /* merge per-server config structures */ 732 resource_checker_cmds, /* table of config file commands */ 733 resource_checker_register_hooks /* register hooks */ 734 };
__APACHE24__
で判定しているのは、Apache2.4とそれ以前で定義方法に差異があるからでしょうか。
728〜732行は http://blog.matsumoto-r.jp/?p=603 を読んでお勉強。
とりあえず今は設定がちゃんとされてますか、の面倒をApache起動時に見るための記述という理解。
リクエストを処理する際に気にするところは、 resource_checker_register_hooks
の中で設定されたhook関数群かな
2. 登録されたhook関数
715 static void resource_checker_register_hooks(apr_pool_t *p) 716 { 717 ap_hook_post_config((void *)resource_checker_init, NULL, NULL, APR_HOOK_MIDDLE); 718 ap_hook_access_checker(before_resource_checker, NULL, NULL, APR_HOOK_LAST); 719 ap_hook_fixups(resource_checker_handler, NULL, NULL, APR_HOOK_LAST); 720 ap_hook_log_transaction(after_resource_checker, NULL, NULL, APR_HOOK_LAST); 721 }
ap_hook_XXXX
はhookさせたいタイミングに応じて、様々な種類がある。詳細は http://d.hatena.ne.jp/dayflower/20081029/1225266220 と http://blog.matsumoto-r.jp/?p=1625 にまとまっている。
今回のものでいくと、
- ap_hook_post_config - 設定初期化時
- ap_hook_access_checker - アクセス制御を行う前(なので、アクセス制御をおこなう)
- ap_hook_fixups - よくわからん・・・
- ap_hook_log_transaction - レスポンス後のロギング処理時
今回の mod_resource_checker
はリソース情報をロギングすることが目的なので、 ap_hook_log_transaction
が重要な仕事をやってそう。
3. ap_hook_log_transaction でやっていること
577 static int after_resource_checker(request_rec *r) 578 { 579 mod_rc_dir_conf *dconf = (mod_rc_dir_conf *)ap_get_module_config(r->per_dir_config, &resource_checker_module); 580 mod_rc_conf *sconf = (mod_rc_conf *)ap_get_module_config(r->server->module_config, &resource_checker_module); 581 mod_rc_rusage *before_resources = dconf->before_resources; 582 583 if (dconf->cpu_utime == INITIAL_VALUE && dconf->cpu_stime == INITIAL_VALUE && dconf->shared_mem == INITIAL_VALUE && 584 dconf->check_status == OFF && dconf->check_all == OFF) 585 return DECLINED; 586 587 int match; 588 struct stat sb; 589 mod_rc_rusage *after_resources; 590 after_resources = (mod_rc_rusage *)apr_pcalloc(r->pool, sizeof(mod_rc_rusage)); 591 mod_rc_rusage *use_resources; 592 use_resources = (mod_rc_rusage *)apr_pcalloc(r->pool, sizeof(mod_rc_rusage)); 593 594 mod_rc_client_data *cdata; 595 cdata = (mod_rc_client_data *)apr_pcalloc(r->pool, sizeof(mod_rc_client_data)); 596 597 if (resource_checker_initialized == 0) { 598 return OK; 599 } 600 601 if (r->main && (stat(r->filename, &sb) == -1) && errno == ENOENT) { 602 return OK; 603 } 604 605 cdata->access_uri = r->uri; 606 cdata->access_file = r->filename; 607 #ifdef __APACHE24__ 608 cdata->access_src_ip = r->connection->client_ip; 609 #else 610 cdata->access_src_ip = r->connection->remote_ip; 611 #endif 612 cdata->access_dst_host = r->server->server_hostname; 613 614 if (dconf->check_status == ON) { 615 _mod_resource_checker_logging(r, 0, 0, NULL, dconf, cdata, MODULE_NAME, "RCheckSTATUS", NULL, r->pool); 616 } 617 618 // threashould check 619 if (before_resources == NULL) { 620 ap_log_rerror(APLOG_MARK, APLOG_NOTICE, 0, r, "%s NOTICE %s: Can not check resource of the request: file = %s", 621 MODULE_NAME, __func__, r->filename); 622 return DECLINED; 623 } 624 625 match = 0; 626 after_resources->cpu_utime = INITIAL_VALUE; 627 after_resources->cpu_stime = INITIAL_VALUE; 628 after_resources->shared_mem = INITIAL_VALUE; 629 630 if (dconf->cpu_utime > INITIAL_VALUE || dconf->check_all == ON) { 631 match = 1; 632 if (dconf->check_all == ON) 633 after_resources->cpu_utime = _get_rusage_resource(r->pool, "ALL", "cpu_utime"); 634 else 635 after_resources->cpu_utime = _get_rusage_resource(r->pool, dconf->utime_process_type, "cpu_utime"); 636 } 637 638 if (dconf->cpu_stime > INITIAL_VALUE || dconf->check_all == ON) { 639 match = 1; 640 if (dconf->check_all == ON) 641 after_resources->cpu_stime = _get_rusage_resource(r->pool, "ALL", "cpu_stime"); 642 else 643 after_resources->cpu_stime = _get_rusage_resource(r->pool, dconf->stime_process_type, "cpu_stime"); 644 } 645 646 if (dconf->shared_mem > INITIAL_VALUE || dconf->check_all == ON) { 647 match = 1; 648 if (dconf->check_all == ON) 649 after_resources->shared_mem = _get_rusage_resource(r->pool, "ALL", "shared_mem"); 650 else 651 after_resources->shared_mem = _get_rusage_resource(r->pool, dconf->mem_process_type, "shared_mem"); 652 } 653 654 if (match == 0) { 655 return OK; 656 } 657 658 use_resources->cpu_utime = after_resources->cpu_utime - before_resources->cpu_utime; 659 use_resources->cpu_stime = after_resources->cpu_stime - before_resources->cpu_stime; 660 use_resources->shared_mem = after_resources->shared_mem - before_resources->shared_mem; 661 662 // unexpected value; resource is negative number 663 if (use_resources->cpu_utime < 0) { 664 use_resources->cpu_utime = 0; 665 } 666 if (use_resources->cpu_stime < 0) { 667 use_resources->cpu_stime = 0; 668 } 669 if (use_resources->shared_mem < 0) { 670 use_resources->shared_mem = 0; 671 } 672 673 if (dconf->cpu_utime > INITIAL_VALUE && use_resources->cpu_utime >= dconf->cpu_utime) { 674 _mod_resource_checker_logging(r, use_resources->cpu_utime, dconf->cpu_utime, dconf->utime_process_type, dconf, 675 cdata, MODULE_NAME, "RCheckUCPU", "sec", r->pool); 676 } 677 678 if (dconf->cpu_stime > INITIAL_VALUE && use_resources->cpu_stime >= dconf->cpu_stime) { 679 _mod_resource_checker_logging(r, use_resources->cpu_stime, dconf->cpu_stime, dconf->stime_process_type, dconf, 680 cdata, MODULE_NAME, "RCheckSCPU", "sec", r->pool); 681 } 682 683 if (dconf->shared_mem > INITIAL_VALUE && use_resources->shared_mem >= dconf->shared_mem) { 684 _mod_resource_checker_logging(r, use_resources->shared_mem, dconf->shared_mem, dconf->mem_process_type, dconf, 685 cdata, MODULE_NAME, "RCheckMEM", "MiB", r->pool); 686 } 687 688 if (dconf->check_all == ON && dconf->json_fmt == ON) { 689 _mod_resource_checker_logging_all(r, use_resources, dconf, sconf, cdata, r->pool); 690 } 691 692 return OK; 693 }
アクセス元IP・CPU使用量・メモリ使用量などかきあつめて、どこまで記録するかの設定に応じてロギング関数に投げてるのかな。
メモ
- 下部のモジュール定義の書き方、処理させたいタイミングに応じてhook関数を設定する、というやり方は他のApacheモジュールでも同じっぽくて、今後読むときはそこから見ていこう
- 様々なhookさせるポイントがあって、むずかしい。
- 調べてもあんまり情報でてこなくて辛い
ほとんど独り言みたいな内容になってしまった。おしまい