特定の文字列を含まないファイル一覧を取得する
hoge
とファイル中に記載されていないファイル一覧を取得したい。
ワンライナーで書けたのでメモ。
find . -name "*.html" -print0 | xargs -0 perl -nle '/hoge/ and close(ARGV) and next; print "$ARGV" if eof(ARGV);'
find
でファイルを読み込む。
perl
のclose(ARGV)
は現在読み込み中のファイルをクローズする操作で、ただ、クローズ直後はファイルポインタがEOFになっただけなので、next
してループを次にすることで、次のファイルを読み込みに相当させる。Perlではループ終了のための構文はbreak
ではなくてlast
だが、上記でnext
じゃなくてlast
を記述すると、プログラム自体が終了してしまう。
雑な解説。
GCPでプロキシサーバ設置squidの導入
Webサイトを別サーバーに移転してあるタイミングでサーバーにアクセスできなくなった。社内以外のネットワークだとアクセスできる模様…
結論からいうと、GCEのサーバに何度かssh
ログインに失敗すると、ping
さえ通らないようになるらしい。(リセットすれば治る)
ただ、そのことに気づくまでにあれこれ試して、プロキシまでたてた。今となっては不要だけどメモだけ。
プロキシサーバ
squid
を使ったよ
プロキシサーバの設置
以下プロキシサーバ側
構成
- Google Compute Engine
- Ubuntu 16.04 LTS
Ubuntu 大好き人間です。はい。
CentOSとかが無難なのかな、とか思いますが、グローバルなシェアでみるとUbuntuの方が今多数派らしい。
squidインストール
$ sudo apt install squid
設定
$ sudo vim /etc/squid/squid.conf
以下コメント。
... # 1190行目 # http_access deny all ... # 1599行目 # http_port 3128 ...
ポート3128と8080はよく使われるポートらしいので避ける
で、以下を末尾に追記。
# noneにしてるけれど任意でいい visible_hostname none # ポート,8080,3128以外を推奨 http_port 43288 # 許可するIPアドレスを記載 acl myacl src X.X.X.X/32 http_access allow myacl http_access deny all # プロキシサーバ接続端末のIP隠蔽 forwarded_for off # プロキシ経由のアクセスをアクセス先に隠蔽 request_header_access X-Forwarded-For deny all request_header_access Via deny all request_header_access Cache-Control deny all
キャッシュクリアしてリスタート
$ sudo squid -z $ sudo service squid restart
次にファイアウォールも設定しておく。
GCPでは管理コンソールから「ネットワーキング」→「ファイアウォール ルール」から、プロキシ用のポートのアクセスを許可するルールを作成し、VMインスタンスに紐付ける。
詳しくはここ↓
ネットワークとファイアウォールの使用 | Compute Engine ドキュメント | Google Cloud Platform
クライアント側の設定
クライアント端末もUbuntu Desktopで接続した。 ubuntuなら「システム設定」→「ネットワーク」→「ネットワークプロキシ」から設定できるので、設定する。
それかexport http_proxy="http://sample.proxy.com"
みたいにすればできるらしい。
いずれにしてもブラウザは再起動しないとプロキシを利用できないようだった。
確認
確認くんというサイトが便利だった。
これで表示されるIPがプロキシサーバのIPならプロキシ経由でアクセスできている。
他
AWSもそうだけど、GCPなら気軽に海外のサーバをプロキシにできるから、IPブロックとかもうまいこと避けられるんでないかな
ziproxy
とかも導入したい
【GAS】Gmailのメール受信をChatworkに通知
zapierがChatworkと連携していて便利。Gmailの特定メール受信時に、Chatworkへ通知させてみたら喜ばれた。
けれども無料プランだと
- 月に100のタスクまでしか処理できない
- 5つまでしか設定を保存できない
という制限がある。
人は無料だと喜ぶけど、有料になったとたんに「はん。まぁ、金払えば便利にはなるわな」となる。切ない。
とりあえず前者だけ解決したくて、今回GASで書いたときのメモ
理想的な流れ
Gmail受信→Chatwork APIたたく→Chatworkに通知くる
現実
GAS定期実行で新規メール確認→新規メール発見したらChatwork API たたく→Chatworkに通知くる
要するにバッチ処理で新規メールを確認して判定する。ただ、おもむろに1分間隔でバッチ走らせてたら夜にメールがきた。
泣いた。
ここ↓をよく読んでおきましょう
https://developers.google.com/apps-script/guides/services/quotas?hl=en
最終的に15分間隔くらいでバッチを回しました。
用意するもの
-
- ビジネスアカウント契約しないと取得できない
- 参考: http://developer.chatwork.com/ja/authenticate.html
-
- 僕はInbox派
Google Apps Script
当然だけど、自分のGoogleアカウントで受信できるメールを通知します。
スクリプトはよ
とりあえずGAS(Google Apps Script)のコードのサンプル。
function run() { var title = "メール通知"; var searchQuery = "from:delivery@mail.com to:me@gmail.com"; var checkSpanMinute= 900; // 起動時間間隔(15分) /* debug var roomId = "1010101"; # テスト用のマイチャットルームID /*/ var roomId = "21212121"; # 通知したいチャットのルームID //*/ var dt = new Date(); dt.setMinutes(dt.getMinutes() - checkSpanMinute); var threads = GmailApp.search(searchQuery); var msgs = GmailApp.getMessagesForThreads(threads); for(var i = 0; i < msgs.length; i++) { var lastMsgDt = threads[i].getLastMessageDate(); if(lastMsgDt.getTime() < dt.getTime()) { break; } for(var j = 0; j < msgs[i].length; j++) { var msgDate = msgs[i][j].getDate(); var msgBody = msgs[i][j].getPlainBody(); var msgFrom = msgs[i][j].getFrom(); var matches = msgFrom.match(/"(.+)".*<(.+)>/) { var subject = msgs[i][j].getSubject(); var postMsg = "[info]" + title + "\n" + Utilities.formatDate(msgDate, 'Asia/Tokyo', 'yyyy/MM/dd hh:mm:ss') + "\n" + "件名:" + subject + "\n" + "[hr]" + msgBody + "[/info]"; // リクエストトークン var token = { "method" : "post", "headers" : { "X-ChatWorkToken" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", // Chatworkの認証トークン }, "payload" : { "body" : postMsg, } }; var apiUrl = "https://api.chatwork.com/v2/rooms/" + roomId + "/messages" var response = UrlFetchApp.fetch(apiUrl, token); } } } }
動作結果 in Chatwork
真っ黒じゃねぇか
解説
var searchQuery = "from:delivery@mail.com to:me@gmail.com";
Gmail検索クエリ。Gmailの検索バー?で入力してみて、通知させたいメールだけヒットするか試してみるといい。
参考:Gmail で使用できる検索演算子 - Gmail ヘルプ
複数条件をスペースで入力するとAND検索になる。リンク先には紹介されていないが、NOTも使えた。
/* debug var roomId = "1010101"; # テスト用のマイチャットルームID /*/ var roomId = "21212121"; # 通知したいチャットのルームID //*/
あんまりGAS関係ないけど このコメントの書き方は
新卒エンジニアでもできる!コメントアウトで同期に差をつける裏技 - Qiita で知った。
debug
と書かれた先頭の行に/
をつけると、デバッグモードのチャットルームIDが有効になる。
//* debug var roomId = "1010101"; # テスト用のマイチャットルームID /*/ var roomId = "21212121"; # 通知したいチャットのルームID //*/
ほらね。すごい。
ちなみにルームIDは、通知させたいチャットを開いた際のURL末尾のridに続く数字のこと。
例えばhttps://www.chatwork.com/#!rid102030
なら102030
がルームID。
var dt = new Date(); dt.setMinutes(dt.getMinutes() - checkSpanMinute);
分単位の計算。現在時刻からcheckSpanMinute
分だけ遡って検索してる
var threads = GmailApp.search(searchQuery); var msgs = GmailApp.getMessagesForThreads(threads);
検索クエリsearchQuery
でGmailを検索してる。
GmailThread
クラスとGmailMessage
クラスの概念をここで把握しておくべきなのだけれど、ざっくり言うとGmailThread
はスレッド(まんまや)。同じ件名でお互いが返信し続けると、Gmailって1つのスレッドで表示されますよね。あのひとまとまりが、GmailThread
クラスのインスタンスとして扱える。
GmailThread
インスタンスには、そのスレッドを構成するGmailMessage
クラスのインスタンスを持つ。
Gmail Service | Apps Script | Google Developers
ここで注意が必要だったのが、それぞれのインデックスの扱い方。
var msgs = GmailApp.getMessagesForThreads(threads); for(var i = 0; i < msgs.length; i++) { var lastMsgDt = threads[i].getLastMessageDate(); if(lastMsgDt.getTime() < dt.getTime()) { break; } for(var j = 0; j < msgs[i].length; j++) { var msgDate = msgs[i][j].getDate(); ... }
上記ではmsgs
が2次元のインデックスを持っているが、msgs[i]
はi
が小さいとスレッド中の最終受信メールの時刻がより新しいものとなる。
msgs[i][j]
のj
では、スレッドi
中のメッセージj
の時刻がより古いものになる。
から、一定時間前のメッセージで走査を打ち切る場合は、i
は0
から、j
はスレッドi
のメッセージ数-1
からインデックスを走査する必要がある。
// リクエストトークン var token = { "method" : "post", "headers" : { "X-ChatWorkToken" : "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", // Chatworkの認証トークン }, "payload" : { "body" : postMsg, } }; var apiUrl = "https://api.chatwork.com/v2/rooms/" + roomId + "/messages" var response = UrlFetchApp.fetch(apiUrl, token);
参考: Class UrlFetchApp | Apps Script | Google Developers
Chatwork APIはヘッダにX-ChatWorkToken
が必要で、個々の認証トークンを記述する必要がある。
こういった独自のヘッダはコードに示したようにheaders
内にKey Value形式で書いたらいい。
ここまでできたら、定期実行のトリガーを仕掛ける。
GASの編集画面のメニューから編集→現在のプロジェクトのトリガー
実行したい関数を設定(この例ではrun
)、「時間主導型」のトリガーにする。当然だが、スクリプトで設定した起動時間間隔に合わせること。
課題・未確認事項
エラー処理は特にしてない。スクリプトの実行時間と起動間隔の兼ね合いで、スクリプト実行中に受信したメールは通知されないかも知れない。
ほか
もっとトリガーの種類ほしい。GASつよい。