それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

IMAP経由やラベル一覧でGmailでラベルが見えない(SPAM/Draftとか)

API 経由でGmailにアクセスしたんですよ。

Gmailのアクセスを調べてて、試しに、SPAMをまとめて削除しようと思ってたらSPAMラベルが見えない

iphoneAndroid からGmailにアクセスしたら、フォルダやラベルが見えない。

Gmailはラベル一覧とIMAPへのエクスポートと、アクセス方法に応じて設定が異なる。

ラベル一覧は可視・不可視設定がある。

Gmailのラベルは可視・不可視が選べるので、むかしむかしに設定した不可視に邪魔されることがある

f:id:takuya_1st:20151225015704p:plain

というわけで。

Gmailでラベルが見えないときは設定を疑えということでした。

bash のシェルスクリプト(関数)でオプション引数を扱う getopts 使い方サンプル

シェルスクリプトで引数オプションを使いたい

my_shell_script -a /usr/bin

みたいに、bashシェルスクリプトでも引数を扱いたい。

getopts を使えば引数が取れる

bash では getopts を使えば、引数の処理を簡単に行うことができて便利。ruby などでは optparseに相当するやつです。

はじめに getopt / getopts の違いについて

全ての初めに。

getoptsについて読む前に知っておかなくちゃいけないことがある。

getopts コマンドとシェルのビルトインの二種類がある。

名前 種類
getopts シェル組み込み
getopt コマンド・ファイル

Google検索はgetopt/getopts を区別しないで結果を出すので注意が必要でした。

今回、調べたのは getopts です。

getopt は/usr/bin にあるコマンドです。

/usr/bin/getopt は、BSDOSX)とGNUlinux )で挙動が異なるため、OSXLinuxでどちらでも使えるようにするため、gnu bash の組み込み関数を使うことにしました。

getopts はシェル組み込み関数です。

今回扱うのは、getoptsシェル組み込み関数です。

getopts の基本的な使い方

getopts の基本的な使い方 は次の通りです。

getopts "引数名" 変数名
使用例

使い方は簡単です。

getopts "a" opts

引数に -a を指定したら opts 変数に中身(a)が入る

複数オプションを入れる

複数書きたいときは、連続してアルファベットを続ける

getopts "abc" opts

オプションで使いたいアルファベットを複数続けて書くだけ。楽チン。

実際に使って試してみる。

適当に関数を作ってgetopts を使ってみます。

function my_func(){
  echo 引数=$1
  getopts "adh" opts
  echo getopts結果=$opts
}

my_func -a
実行結果
引数=-a
getopts結果=a
未知の引数の場合
my_func -b
実行結果
引数=-a
/Users/takuya/Desktop/test.sh: illegal option -- b
getopts結果=?

何も書かなくても未指定の引数にはエラーを出してくれる。便利!

シェルの言語がja_JPであれば

takuya@~$ my_func -x
-bash: 不正なオプションです -- x

エラーメッセージをローカライズして表示してくれる。いいね

エラー処理を自分でやる?

組み込みのエラー処理はいらないと思う場合、

illegal option –を無視するには

先頭にセミコロンを置く
getopts ":adh" opts

こうすると、エラーを自分でハンドリングできる。

複数オプション の例

先ほどの関数に複数オプションをつけてみると。。。

my_func -a -d
引数=-a -d
getopts結果=a

複数オプションは考慮されない。 (後述するが、複数回getoptsを呼び出すことで処理できる。)

オプションを指定しない場合

getopts を設定した関数へ、なにもオプションを指定せずに起動すると・・・

my_func
引数=
getopts結果=?

結果は ? になる。

そのため、"?“ を判定してヘルプを表示するようスクリプトを記述する。

”?”(未知=ヘルプ)などと覚えておけばいいでしょう。

-a オプションではなく、ただの引数を入れる

ハイフン付きのオプションでななく、よくある引数を入れてみるとどうなるか。

my_func aaaaaaaaa
引数=aaaaaaaaa
getopts結果=?

引数がない時と同じになる。

オプション引数を扱う。

オプション付き引数を入れる。つまり、オプションで引数を入れてみる。

my_func -a my_value

このように、設定値付きのオプションを使う、オプション引数を使う。

“a:” 文字+”:”でオプション引数

オプションに引数をつけるには、getopts で「:」を追加する

引数が一つのとき
getopts "a:" OPT
引数が二つのとき
getopts "a:b:c:" OPT
引数が三つのとき
getopts "a:b:c:" OPT
オプション付き引数を処理しない場合

オプション付き引数を処理しない場合は連続して文字を続けるだけ

getopts "abcdefg" OPT

オプション引数のサンプル

シェルスクリプトは次のように記述した $OPTARG にオプション引数が入る点が違う。

function my_func(){

  echo 引数=$@
  getopts ":a:" opts
  echo getopts結果=$opts
  echo $OPTARG

}
my_func -a aaaaaaaaa

実行結果は次の通り

引数=-a aaaaaaaaa
getopts結果=a
aaaaaaaaa

ポイントは、$OPTARG にオプションの引数が入る

複数オプションを使う

ここまでで、基本的な使い方がわかったので、実際にありそうなオプションを取り扱ってみたいと思う。

そのままでは複数オプションを扱えないので、複数回 getopts を使う。

複数回の getopts 呼び出し

先ほど、複数個のオプションを処理できないと書きましたが、getoptsを複数回呼び出せば、複数個のオプションを処理できます。

function my_func(){

  echo args=$@
  getopts ":a:b:" OPT
  echo $OPT
  echo $OPTARG

  getopts ":a:b:" OPT
  echo $OPT
  echo $OPTARG

}
my_func -a aaaaaaaaa -b bbbbbbbbbbbbb

このようにgetoptsを何回も処理したら

実行結果が次のようになる。

args=-a aaaaaaaaa -b bbbbbbbbbbbbb
a
aaaaaaaaa
b
bbbbbbbbbbbbb

ここでのポイントは。複数回getoptsを適用すれば、複数個のオプションに対応できる。という点

複数オプションをループで処理する

ここまできて、漸くネットで見かけるサンプルに近くなる。

function my_func(){

  echo args=$@

  while getopts ":a:b:" OPT ; do

    echo $OPT
    echo $OPTARG

  done

}
my_func -a aaaaaaaaa -b bbbbbbbbbbbbb

複数オプションを取得するには、なくなるまでwhileループを回すのが基本

実行結果
args=-a aaaaaaaaa -b bbbbbbbbbbbbb
a
aaaaaaaaa
b
bbbbbbbbbbbbb

while で処理するときは caseとともに使う。

function my_func(){

  echo args=$@

  while getopts ":a:b:" OPT ; do
    case $OPT
      a)  echo $OPT
           echo $OPTARG
           ;;
      b)  echo $OPT
           echo $OPTARG
           ;;
     esac
  done

}
my_func -a aaaaaaaaa -b bbbbbbbbbbbbb

これで、getopts を使える。

getopts と while + case を組み合わせて戦うことで、シェルスクリプトでもオプションと引数つきオプションを扱えることがわかった。

ただし、whileループで処理した場合引数なしには対応できない

while ループを記述したコマンドを オプションなしで起動すると・・・

my_func aaa
args=aaa
(getopts のwhile ループでは処理されない

引数が指定されてない時に注意が必要

ナニも引数が指定されない場合は、getoptsはシゴトをするが、exit(1) するのでwhile と相性が悪い

while に入れた時には、結果は空っぽになる。

“?” はどこいった?

ただし、"?“ はきちんと処理されている。 while が処理終了になるので、while 中の case に処理がこないだけ。

function my_func(){

  echo args=$@

  getopts ":a:b:" OPT
  echo $?
  echo opt=$OPT
}
my_func -a hoge
my_func
結果
args=-a hoge
0
opt=a
args=
1
opt=?

OPTには ? が入るが、コマンドの実行結果ステータスが 1 になるので whileから抜けてしまう。

なので、while getopt でオプションが全く指定されない場合の ?をwhile中で検出することが出来ない。

ここまでのまとめ

ここまでの実験でわかったことをまとめた。

  • getoptsはオプション・引数付きオプションを処理することができる。
  • getoptsは複数回起動すると複数のオプションを処理できる
  • getoptsは while と case 句を組み合わせて処理をする。
function my_func(){

  echo args=$@

  while getopts ":a:b:" OPT ; do

    case $OPT in
      a)
        echo -a の引数 $OPTARG
        ;;
      b)
        echo -b の引数 $OPTARG
        ;;
      : )
        echo "ここ"
        ;;
      \? )
        echo nothing matched
        ;;
    esac

  done

}
my_func  -a aaa
my_func
my_func -c ccc

while とともに使った場合

検出ができるのは、「不正なオプション」を渡した時に限られる、「オプションが全く未指定」は検出ができない。別途考えないとダメなようだ

注意: getoptsをfunction内で利用す場合

getopts 複数回よびだせる、そのときにどこまで処理したかを保存する。

どこまで処理したかは、変数 $OPTIND(オプションインデックス)に保存する。

そのため、getopts は OPTINDを使うので、function で使うときは、OPTIND をグローバル汚染させない注意が必要

function path() {

 local OPTIND OPTARG OPT ## ここ重要

  while getopts 'ha:d:' OPT ; do
    case $OPT in
      d)
        echo "-D entered"
        ;;
      a)
        echo "-A entered"
        ;;
      \?)
        ;;
    esac
  done
}

local OPTIND を書かないと、グローバル変数に値が入っちゃうので、getopts が含まれる関数を何度も呼び出せない。

local 宣言があるとき

function 内に local 宣言をちゃんと書いた場合・・・

function path() {

 local OPTIND OPTARG OPT

  while getopts 'ha:d:' OPT ; do
    case $OPT in
      a)
        echo "-A entered"
        ;;
    esac
  done
  echo end
}
### ここで関数の実行
path -a aaa
path -a aaa
path -a aaa

実行と結果

-A entered
end
-A entered
end
-A entered
end

local 宣言がないとき。

function path() {
# local 宣言をコメントアウト
#local OPTIND OPTARG OPT 

  while getopts 'ha:d:' OPT ; do
    case $OPT in
      a)
        echo "-A entered"
        ;;
    esac
  done
  echo end
}
path -a aaa
path -a aaa
path -a aaa

実行結果

-A entered
end
end
end

このようにlocal宣言がないと変数$OPTIND が作用して、オプションを取れなくなる。

1つのファイルでシェルスクリプトを記述するのなら問題ないのだけれど、関数を作って連続して使うなら変数を共有しない工夫が必要

getoptsをファイルで使う場合

getoptsをファイルで使う場合は、環境変数をexport しない限りファイル内部で完結するので、管理は難しくない。

my_script.sh
#!/usr/bin/env bash
  while getopts 'ha:d:' OPT ; do
    case $OPT in
      a)
        echo "-A entered"
        ;;
    esac
  done
  echo end

ファイルに記述した場合

my_script.sh -a aaaa
my_script.sh -a aaaa
my_script.sh -a aaaa

としてもOPTINDはファイルごとに確保されるため全然影響がなく、問題ない。

getopts まとめ

  • getopts はシェル組み込み関数(builtinコマンド)
  • getopts “abc” とかけば -a -b -c とオプションを作れる
  • 複数個のオプションを一度に処理するには getoptsを複数回呼び出し
  • 複数個のオプションを処理するには while + case を使う
  • オプション引数を使うには getopts “a:b:c"とする
  • エラー処理を自分でやるには getopts “:a” と先頭に「 : 」をつける
  • 関数内で getopts を使うときは local OPT をつける

参考資料

http://stackoverflow.com/questions/16654607/using-getopts-inside-a-bash-function

au-Wifi の提供がスマホに限定される?

au Wi-Fi SPOTマルチデバイスサービス」がリニューアル してた

ご利用方法と対象機種の変更に伴い、これまで提供してきた専用アプリ(au Wi-Fi接続ツール)では2016年2月1日よりマルチデバイスサービスをご利用いただけなくなります。

え、ちょっとまてよ。いまで、PCから無料で使えたのが使えなくなるってことですかね。

PCから au-Wifi つながらない阿鼻叫喚が待ってる。

ちょっとまだ追いきれてないんだけど

www.au.kddi.com

いままでは無料でWiFi接続ツールで使えるようにしたけど、これからはWi2を使ってくれヨロシクってことですね。

影響のある料金プラン

これらのプランでは、引き続き無料(ただし新規加入・変更は出来ない) - LTEフラット - LTEフラット(V)

通常はこれからは月額300円のプランが標準になる。

  • データ定額2/3/5/8/10/13
  • データ定額2(V)/3(V)/5(V)/8(V)/10(V)/13(V)
  • データ定額2(VK)/3(VK)/5(VK)/8(VK)/10(VK)/13(VK)
  • LTEフラット cp(f・2GB)
  • LTEフラット cp(1GB)
  • ジュニアスマートフォンプラン
  • シニアプラン
  • シニアプラン(V)

www.au.kddi.com

ということです。

影響のあるSSID

これからのプランでは次のSSIDが有料になる。

  • Wi2
  • Wi2_club
  • Wi2_free
  • wifi_square
  • Wi2premium
  • Wi2premium_club
  • UQ_Wi-Fi

ご利用条件|公衆無線LANサービスWi2 300

今まで使えたSSID

au_Wi-Fi」(WPA2)、「au_Wi-Fi2」(WPA2エンタープライズ)、「Wi2premium_club」(WPA2)、「Wi2_club」(WPA2)、「UQ_Wi-Fi」(WEP)、「Wi2premium」(暗号化なし)、「Wi2」(暗号化なし)、「wifi_square」(暗号化なし)

つまり、iOS/Android以外をau-WiFiから追い出すってことですね。

au_Wif2 がEAP-SIMだから、au-Wifiは消えていくんでしょうか。

まぁ速く言えば

いままでPC向けもau-wifi で提供したけど、スマホ以外は、wi2に丸投げするからよろしく。ってことですね。

これからはPCなどでWifi使いたきゃ300円(税抜)払え、Wi2よりは50円ほど安いぞってことですね。

au は良心的?

猶予期間を1年位あけてるのと、残存旧プランへの救済措置を作ってるのは、やっぱりau は良心的なキャリアだなぁと思うわけです。

こうやって徐々に値上げされていくんですね。

WiMAX1まきとりで、使えないau_WiFiを巻き取りつつ、インフラ更新をwi2に丸投げして、自社はau_WiFi2でSIM認証でガードかけていくのかな

5G見据えたらwifiはイラないってことなんでしょうねぇ。

curl+xpath から始めるお手軽スクレイピング(2)

この記事は前回の続きです。

curl とxpath でお手軽スクレイピング

前回までで、xpath + curl + cookie を使いました。

xpath はとても便利なので、基本的な使い方を再掲しておきます。(以前にまとめたもののですが)

xpath 内容
//* 全てのノード
//a 全ての<a> ノード
(//a)[1] 全ての<a> ノードを取得して、最初の1個
(//a)[2] 全ての<a> ノードを取得して、2番め(配列アクセス)
(//a[1]) 親ノード中の最初の1個の<a>をすべて
//a/span span ノードで、親が<a>のものをすべて
//a/@href aノードのすべてのhref属性
//a/text() aノードのすべてのtext()表現
//a[@href="/index.html"] aノードのうち href属性が"/index.html"と合致するモノすべて
//a[contains(@href,"index.html")] aノードのうち href属性に index.html を含むものすべて
//title | //meta title と meta タグを両方
//img[ contains(@src,'jpg') or contains(@src,'png')] img ノードで src に jpg/pngを含むものすべて
//div[ contains(@class,'link') and contains(@class,'book')] div.link.bookに相当するもの
//form[ ./input[name="username"] ] 子ノードに //input[name="username"]を持つform ノード
//div[@id=main]//form form ノードで、親が div[@id=main] の物をすべて
//div/* div の子要素すべて
//div//* div の子孫要素をすべて
//table//td[2] table タグで2番めのtdのもの(2列目をすべて)
//*[@id] id属性があるものをすべて
id("tid_123") id属性がtid_123のもの(id="tid_123")

xpath の練習

このページに含まれる a 要素を列挙する

curl -s  http://takuya-1st.hatenablog.jp/ | xpath "//a/@href"

このページに含まれる title と meta を取り出す。

curl -s  http://takuya-1st.hatenablog.jp/ | xpath "//title | //meta"

このページに含まれるform で2番目のものを取り出す。

curl -s  http://takuya-1st.hatenablog.jp/ | xpath "(//form)[2]"

curl + xpath + md5sum で更新チェック

ページの更新チェックを、要素を内部HTMLの変化として考えて、要素の変化を追いかけて、更新チェックをする

url="http://localhost/"
xpath_exp="(//div[contains(@class, 'main')])[2]"
digest=`curl -s  $url | xpath $xpath_exp 2>/dev/null | md5sum `


while true ;  do
  current=`curl -s  $url | xpath $xpath_exp 2>/dev/null | md5sum `
  if [[ $digest != $current ]] ; then
    echo changed!!
    sendmail ほげほげ
    digest=$current
  fi
  sleep 1
done

このように、ページの更新をcurlxpath で確実に追いかけることができます。

curl で連続ページ取得

curl でも、連続したページの取得ができます。それが --next オプションです。

--next によるフォーム送信からのデータ取得

next を使うことで、通常のクローラーを描くような動作をcurl にも行わせることができます。

以下の例は、pitapa.com にログインして、トップページへ遷移している例です。

curl -v -k  -c  pitapa.cookie.yml -F id=takuyaXXX -F password=XXXXX \
  https://www2.pitapa.com/member/login.do\
 --next -k -c  pitapa.cookie.yml    https://www2.pitapa.com/member/top.do

next は続けていくつでもかけます。便利!

もっとまとめてデータを取得したい

URLの一覧を列挙して、バンバンアクセスして取得することができます。それが --config オプション

page.conf ファイル

アクセスしたいURLを列挙してページを取得に行きます。

url="http://www.yahoo.co.jp/"
output="yahoo.html"

url="https://qiita.com"
output="qiita.com.html"

url="http://b.hatena.ne.jp/"
output="hatebu.html"

ページの一覧はxpath で作っておけばいいと思います。

連続取得

curl に--config/-K オプションをつけると連続してデータ取得をバッチ処理してくれます。

curl -s -K page.conf 

これで、xpath で作成したアクセスURL一覧へどんどんアクセスすることが可能になります。便利

user-agent なども指定できる

config の名前の通り、 curl に渡すコマンドオプションも記述できます。

user-agent="Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.48 Safari/537.36"

url="http://www.yahoo.co.jp/"
output="1.html"
url="http://www.yahoo.co.jp/"
output="2.html"
url="http://www.yahoo.co.jp/"
output="3.html"
url="http://www.yahoo.co.jp/"
output="4.html"
url="http://www.yahoo.co.jp/"
output="5.html"
url="http://www.yahoo.co.jp/"
output="6.html"
url="http://www.yahoo.co.jp/"
output="7.html"

libcurl オプション

curl コマンドからしか使えないってこともないです。C言語のソースも吐いてくれます。

curl --libcurl get_urls.c -s -k -K curl.conf

こうすると、get_urls.c が生成されて

/********* Sample code generated by the curl command line tool **********
 * All curl_easy_setopt() options are documented at:
 * http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
 ************************************************************************/
#include <curl/curl.h>

int main(int argc, char *argv[])
{
  CURLcode ret;
  CURL *hnd;

  hnd = curl_easy_init();
  curl_easy_setopt(hnd, CURLOPT_URL, "http://www.yahoo.co.jp/");
  curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
  curl_easy_setopt(hnd, CURLOPT_USERAGENT, "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.48 Safari/537.36");
  curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
  curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYPEER, 0L);
  curl_easy_setopt(hnd, CURLOPT_SSL_VERIFYHOST, 0L);
  curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);
(以下略

よく使うアクセスパターンをC言語コンパイルでコマンド化することが可能になります。楽しい。

まとめ

curl って便利なので、スクレーパーを作る際に大変重宝します。

xpath 参考資料

http://yakinikunotare.boo.jp/orebase/index.php?XML%2FXPath%2FXPath%A4%CE%BD%F1%A4%AD%CA%FD

たのしいXML: XPath(基礎編)

https://sites.google.com/site/shin1ogawa/xsl/xpath

http://os0x.g.hatena.ne.jp/os0x/20080620/1213987223

find で指定のフォルダを除外するには

find コマンド結果多すぎて除外したいフォルダがありませんか?

find で除外したものといえば、.git や ruby だったら bundle/vendor など、find の結果から除外するには

find の -not オプションを使います

find は「検索条件」を列挙するタイプのコマンドなので、検索条件に -not をつけて否定形にすればいいわけです。

find . -not -iwholename '除外したい名前'
.git を無視する例。

一番使いそうなのがこれ。.git

find . -not -iwholename '*/.git/*'

-name と -iwholename とは?

find のオプションで、 -name と -iwholename は少し違う

  • -name : 自身のファイル名にマッチ
  • -wholename : 自身のファイルのパス名にマッチ
  • -iwholename : wholename のCaseInsensitive版

たとえば 、vendor/bundleについて -name / -iwholename でマッチすると

次のような結果になる。

名前 オプション 結果
vendor -name 'vendor' マッチする
vendor/bundle -name 'vendor' ×
vendor -iwholename 'vendor' マッチする
vendor/bundle -iwholename 'vendor' マッチする

のように検索結果のパス名(ディレクトリ名)にマッチさせることが出来る

-not -iwholename の意味

-iwholenameで .git をパス名に持つのをマッチさせて、それを -not で否定形にしている。

理屈がわかれば便利ですね

alias できない困った問題

.git を常に無視したいと思っても、find コマンドの性質上、検索パスは絞込条件の前に設置する必要がある。

find path -検索条件 -検索条件 -検索条件 #出来る
find  -検索条件 -検索条件 -検索条件  path # できない

そのために、alias をつけておくことが出来ない。

alias find="find $@ -not -name ss" # 出来ない

どうしてもやりたければfunctionを書くしか無いです。

function find { $( which find ) "$@"  -not -iwholename '*/.git/*'  ; }

関数書くしか解決策がないけども、function 使うのが手軽でベターな解決方法。

参考資料

http://stackoverflow.com/questions/2314643/how-can-i-get-find-to-ignore-svn-directories

Chrome(OSX)のパスワード・クッキーを取り出すコマンド作った

Mac OSX のChromeのパスワードを取り出すツールを書いた。

takuya/chrome-storage · GitHub

なぜ書いたのか

OSXChromeが、Keychains.app に同期しなくなったので、インポートするために仕方なく書きました。

いままではKeychainを見ればパスワードを回収できたのですが、OperaSafariFirefoxChromeがそれぞれ別管理になって、別々にアカウント同期でパスワードを持っていくのですが、どれが新しくてドレが古いか全くわからなくなりそうでした。

Chromeの管理からパスワード取り出せば良いのですが、chrome://settings/passwords のパスワードチェックがめんどくさい。ちょっと視認性の悪いUIですよね。

いままではローカルKeychainにパスワードつくってiCloudに移動すればよかったのに・・・Windowsの悪夢に逆戻りだ・・・

Opera/chrome のクッキーとパスワードのデコード

Chromium のパスワードは $PROFILE_PATH/Login Dataのファイルに保存されています。ファイルはSqlite3のデータベースになっています。そのファイルの中身でパスワードは暗号化されて保存されています。

暗号化されたパスワードは、Keychain.app にあるsafe storageに保存された文字列で復号化出来ます。

ダウンロード先

github.com

safe storage が幾つかある。

Opera(stable/beta) とChromeがそれぞれ使っています。

ここに保存されたパスフレーズでブラウザ中の暗号化データをデコード出来るようになっています。

f:id:takuya_1st:20151216034018p:plain:w600

暗号化・復号化処理も含めたブラウザのソースコードは公開されてるので、わたしたちはブラウザから平文でパスワードを得ることが可能になります。これからも安心して使える。ソース公開って素晴らしい

Firefoxはどうしてるんだろう・・・

パスワード・クッキーのデータベースの構造

パスワードとクッキーのデータベースは、次の通りのテーブル構造に格納されていました。

パスワードテーブル
CREATE TABLE   "logins"     (
    origin_url  VARCHAR    NOT   NULL    ,
        action_url  VARCHAR    ,
        username_element    VARCHAR    ,
        username_value  VARCHAR    ,
        password_element    VARCHAR    ,
        password_value  BLOB    ,
        submit_element  VARCHAR    ,
        signon_realm    VARCHAR    NOT   NULL    ,
    ssl_valid   INTEGER    NOT   NULL    ,
    preferred   INTEGER    NOT   NULL    ,
    date_created    INTEGER    NOT   NULL    ,
    blacklisted_by_user INTEGER    NOT   NULL    ,
    scheme  INTEGER    NOT   NULL    ,
    password_type   INTEGER    ,
    possible_usernames  BLOB    ,
    times_used  INTEGER    ,
    form_data   BLOB    ,
    date_synced INTEGER    ,
    display_name    VARCHAR    ,
    icon_url    VARCHAR    ,
    federation_url  VARCHAR    ,
    skip_zero_click INTEGER    ,
    generation_upload_status    INTEGER    ,
    UNIQUE      (
    origin_url  ,
        username_element    ,
        username_value  ,
        password_element    ,
        signon_realm    )
        )
        ;
クッキーテーブル
CREATE TABLE   cookies     (
    creation_utc    INTEGER    NOT   NULL    UNIQUE  PRIMARY KEY ,
    host_key    TEXT    NOT   NULL    ,
    name    TEXT    NOT   NULL    ,
    value   TEXT    NOT   NULL    ,
    path    TEXT    NOT   NULL    ,
    expires_utc INTEGER    NOT   NULL    ,
    secure  INTEGER    NOT   NULL    ,
    httponly    INTEGER    NOT   NULL    ,
    last_access_utc INTEGER    NOT   NULL    ,
        has_expires INTEGER    NOT   NULL    DEFAULT 1  ,
        persistent  INTEGER    NOT   NULL    DEFAULT 1  ,
    priority    INTEGER    NOT   NULL    DEFAULT 1  ,
    encrypted_value BLOB    DEFAULT '' ,
    firstpartyonly  INTEGER    NOT   NULL    DEFAULT 0  )
        ;

データベースからデータを取り出して、復号化

復号化はそんなに難しいものではなく、WEBを探したら色々出てきます。WindowsWin32を使っていて、linux/osxはキーチェンに保存したパスフレーズとhmacを使ったOpensslを使っているようだ

次の例は、ruby で復号化を試みた箇所です。 引数 passの部分は、Keychainから拾ってきます。

    def decrypt(encrypted_value, pass ) 
      iter = 1003
      key_len = 16
      salt = "saltysalt"
      iv = " " * 16

      return if encrypted_value.size < 3

      key = OpenSSL::PKCS5.pbkdf2_hmac_sha1(pass, salt, iter, key_len)

      cipher = OpenSSL::Cipher::AES.new(128,:CBC)
      cipher.decrypt
      cipher.iv = iv 
      cipher.key = key

      data = encrypted_value
      data = data[3,data.size]

      return cipher.update(data) + cipher.final
    end

取り出したID/PASSはKeychainに

security コマンド を使うことで、パスワードをKeychainに書き込むことが出来ます

 security add-internet-password -a ユーザー名 -s サーバー -w パス   -p 対象のフルURL  -U

これで、しばらくは生き延びられそうです。

関連記事

ChromeのCookieをプログラムから使う - それマグで!

chrome のCookieを取り出す。(暗号化Cookieの複合化でデコード済テキストを取り出す) - それマグで!

MechanizeでChromeのCookieを扱って面倒なログインを飛ばす - それマグで!

httpOnlyなCookieとは? - それマグで!

Chrome のパスワードがOSX Keychains に保存・同期しなくなった - それマグで!

bashのalias に引数を渡すには?

Bash のAliasに引数を渡す。

何も考えずに、Aliasをするとそのまま渡される。

alias some=echo
some aaaaaaa

alias は実行前に、bashが解釈するために some aaaaaaaecho aaaaaaa` に展開される。

出来ない。

なので次のようなことは出来ない。

alias git-push-to='git push "$@" master'

これは、bash の実行前に git-push-to remoteA git push "" master remoteA と展開されてしまう。

展開順について。

先の例は、展開が次のようになる。

git-push-to remoteA 

これは、次のように展開。

git push "" master remoteA 

引数は受け取れない。

引数は受け取れない。なぜなら、単純な置換がされるだけだから。

bashのコマンド引数を順番を変えて、aliasに渡すには?

alias でなく関数を使う

まぁ頻出の話題なので、これくらいは基本ですよねってことで。

alias fooo="/path/to/cmd $@ -opts" は出来ない

alias fooo="/path/to/cmd --opts $@ " # できる
alias fooo="/path/to/cmd $@ --opts" # 出来ない
funciton fooo (){ /path/to/cmd $@  --opts } # 出来る

というわけで、alias だとoptionsと引数の順番を指定できないのです。

代わりにFunctionを使うって話です。

引数はと$@ 使っておけば大丈夫です。

  • $@ 引数全部
  • $1 一個目
  • $2 二個目
  • $3 三個目

のように引数を渡せる。

function はbashrcに

functionは ~/.bashrc などに記述しておくといいでしょう。

echo function foo {} >> ~/.bashrc

もし.bashrc をデフォルトから汚したくない!と思う人は(まれでしょうが)

echo source .bashrc.takuya >> .bashrc
echo function foo {} >> ~/.bashrc.takuya

などと、自前の.bashrcをロードする設定を.bashrcに書いておけば解決ですね。

若しくはコマンドファイルを作る

関数を作る以外には、「コマンド」を作るというのが太古から習わしです。

touch fooo
chomod +x fooo
vim fooo
mv fooo ~/takuya/.bin
export PATH=~/takuya/bin:$PATH

コマンドファイルを作って、PATHを通す。

fooo

コマンドファイルには次のように記述します。

#!/usr/bin/env bash

/path/to/cmd $@ 

記述することはfunciton と同じです。

ファイルを作ると管理が面倒?

一番手っ取り早いのでファイルを作る手段も知っておくと便利です。

function とファイルをどちらを使うべきか

好きな方でいいです。管理の容易さ、一覧性などを考えて好きな方で良いと思います。

ただし、zsh/bash などを使い分ける場合や、ユーザーを切り替えてsu/sudo する場合は「ファイルの方がいいと思います」

function は個人専用だったりシェル・スクリプト中で使うものだと思います。

あれ?これってalias?function?

あれれ?このコマンドってalias のfunciton なの?それともコマンドファイル?

aliasを作りまくってるとわからなくなるので

  • hash
  • type

で確認します。

hash / type の例

type で現在のコマンドがなにか分かります。hash でそのコマンドがどのようにハッシュ(キャッシュ)されているかが分かります。

hash
takuya@~ $ hash
hits    command
   1    /usr/local/bin/rm-trash-by-takuya
   0    /bin/rm
type
takuya@ ~ $ type rm
rm は `rm-trash-by-takuya' のエイリアスです

bashはコマンドをなんどもPATH探索しなくてもいいようにhashテーブルに読み込んでいます。

追記

正確には shopt -s expand_aliasesしているときの動作なのだが、expand_aliasesなど今更無効にできるわけもなく

過去資料

bash(csh)のhashとか言う、気づかないけど便利な機能 - それマグで!

シェルにコマンドが存在するか調べる - それマグで!

更新

2021-06-04 更新。

Chrome のパスワードがOSX Keychains に保存・同期しなくなった

chrome がkeychainsに保存しなくなった。

数カ月前から、KeychainsにWEBログインパスワードが存在しないな、、おかしいなと思ってた。

そのうち調べようと思って、ようやく調べて、驚愕した

OSX 版 Chrome は Keychains にパスワードを保存できなくなった

とのこと。

最初なんでこんなことになったのか理解できなかったが、どうやら、OSXのアップデートによってKeychainsにアクセスできるのが、AppStore経由のAppのみになったらしい

ということで、AppStore経由してないものはSafariとパスワードを共有できなくなった。

そのため、もう面倒だし、Keychainをサポートを外してGoogle Chromeは内部にキーチェーンを保存することになったらしい。

えええ、不便だ・・・不便だよ

変更はicloudキーチェーンに関するものだけだろうに、キーチェーンごとバッサリカットですか。。。

細かい話

Safariは保存済パスワードがiOS/OSXで同期するために、iCloud キーチェーンを使う。

iCloudキーチェーンはApp Storeのアプリからは使える。Chromeは非App Storeなので無理。

問題はiCloudキーチェーンの感じ。

ただし、iCloudキーチェーンを使ってない場合はChromeに保存可能なはずだが、キーチェーン関連の機能をChrome側がバッサリカット(←私ここで影響でた)

Firefoxなども同様。

こればっかりはApple vs Googleの関係性も相まってもう解決しないと思われる。

というか、すでにローカル・キーチェーンにあるパスワードを一切参照しなくなったのは辛い。

私も、パスワードの管理方法を変える必要が出てきた。

参考資料

Issue 466638 - chromium - Remove OS X Keychain integration for saved passwords - An open-source project to help move the web forward. - Google Project Hosting

Knowledge for Google Products: 【備忘録】Chroem45のMac用パスワード管理方法が変更(Macキーチェーン→Chrome内部へ)

https://productforums.google.com/forum/?hl=ja#!topic/chrome-ja/9K4rvWBGkpc;context-place=forum/chrome-ja

OSX のMACアドレスをランダムに切替コマンド

OSXMACアドレスを手軽にランダマイズ

無線LANとか、ランダムなMACアドレスで認証してMACアドレス認証が有効になってるかチェックしたいことがあります。

MACアドレスで認証が有効に働いているかは、MACアドレスをランダムに変更してチェックするのが手軽だと思いました。

MACアドレスっぽい乱数をopenssl で作る

openssl で乱数を使ってMACアドレスに許容される乱数を作ります。

openssl rand -hex 6 | sed 's/\(..\)/\1:/g; s/.$//'

コマンド

gist81cdef93ff867e7686e7

2015/12/31追加 単純な乱数だとエラー

単純な乱数だと、MACアドレスとして正しくないのか、設定できないことが頻発した。そのため設定失敗したら、リトライするように書き換えた。

また、コマンドオプションとソースを整理してみた。

ほかに、極力パスワード再確認が減るように実行コマンドを見なおした。

2021-01-27

誤字修正

2022-04-20 追記

macbook で T2 搭載(2018 mbp 以降 ) では、MACアドレスというか、そのもとになるWiFiバイスが、OS管理下にないのでMAC-Addressの書き換えはできません。

かといって、iOSみたいに、WiFi接続時のMacアドレス匿名化もできません。中途半端でAppleが無視のバグです。諦めるしかありません。

curl とxpath でお手軽スクレイピング

この記事は [クローラー/Webスクレイピング Advent Calendar 2015] の一つとして書きました。

公開遅いけど。ごめんね

この記事の目標

curl コマンドの使い方を覚えつつ、スクレイピングをやっていきます。

この記事で紹介すること

用意するもの

知っておくと便利な知識

js への対応

基本方針は「JSに対応しない」

だって、リクエストヘッダ見てたらわかるもん。

curl コマンドでWEBページを取得する

スクレーパをするまえに curl コマンドを紹介します。

curl コマンドは libcurl をコマンドライン使うものです。 curl コマンドはコンパイルオプション次第で http2 / scp / ssh / ftp などほとんどのファイル転送に対応可能です。 おもにHTTPdサーバー への アクセスするのに使います。

curl コマンドを覚えよう

curl コマンドの基本

curl http://qiita.com

curl コマンドで HTTP HEADを見る

curl -I http://qiita.com

curl コマンドでHTTP 302/301 に追従する

curl -L http://qiita.com

 curl で特定のデータを保存する

curl -L http://qiita.com > out.html

 ファイルを保存

curl http://cdn.qiita.com/assets/siteid-reverse-9b38e297bbd020380feed99b444c6202.png > out.png

 URLのファイル名で保存

curl -O https://i.gyazo.com/f609d81c30b580c9015a890643ecc604.png

 サーバーとのやりとりを詳細に表示

curl -v -L http://qiita.com > out.html

 進捗率の代わりにプログレスバーを表示

curl  -#  -O URL

 プログレスバーを一切非表示

curl -s  URL

これくらいを覚えておけば、ほとんどの場合に対応できます。

なぜcurl なのか?

スクレーパーなのになぜcurl のお話をしているのかというと、スクレイピングを作る上で curl は不可欠なツールなのです。

欲しいコンテンツがメインディシュとしたら、ブラウザはレストラン。プログラム言語はコンビニ、curl は「お箸・フォーク」です。美味しくいただくために不可欠なツールです。ちなみに xpathは取り皿=食器ですね。

curl を用いたスクレイピング

curl+ grep でサイトの情報を取り出す。

基本中の基本です。

curl https://qiita.com | grep  title

しかし結果が、、汚い・・・美しくない。

takuya@~/Desktop$ curl -s  https://qiita.com | grep  '<title>(.+)</title>'
1:<!DOCTYPE html><html xmlns:og="http://ogp.me/ns#"><head><meta charset="UTF-8" /><title>Qiita - プログラマの技術情報共有サービス</title><meta content="width=device-width,initial-scale=1" name="viewport" /><meta content="Qiitaは、プログラマのための技術情報共有サービスです。 プログラミングに関するTips、ノウハウ、メモを簡単に記録 &amp;amp; 公開することができます。" name="description" /><meta content="summary" name="twitter:card" /><meta content="@Qiita" name="t(いかりゃく

curl + grep でサイトの情報を綺麗に取り出す

grep -o オプションを使う

curl  https://qiita.com | grep -o '<title>(.+)</title>'

結果はほら綺麗。

$ curl -s  https://qiita.com | grep -o '<title>(.+)</title>'
<title>Qiita - プログラマの技術情報共有サービス</title>

curl + grep -o でそこそこ便利になりますね。

curl + m5sum 

取得した内容をmd5sum にかける

curl -s   http://takuya-1st.hatenablog.jp/entries/2015/12/11 | md5sum

これにより取得した内容が同じかどうか検出が可能になる。

脚注 last-modified や e-tag を使うべきなんだろうが、昔から糞みたいなブログ実装が多くて304 Not Modified を返さないサイトが多すぎるんですよ。むかしから妙竹林の代表例はCA

curl + md5sum + mail 

サイトに更新があったら通知する。シェルスクリプト

curl + md5sum で更新監視なら、3分で書けるよ。カップ麺待ってる間にできちゃうね。

url="http://localhost/"
digest=`curl -s  $url  | md5sum `


while true ;  do
  current=`curl -s  $url  | md5sum `
  if [[ $digest != $current ]] ; then


    echo changed!!
    sendmail ほげほげ
    digest=$current
  fi
  sleep 1
done

サイトが変化したら、MD5の結果が変わるので、その結果を見つけて通知します。

これだと毎秒見に行ってます。むかしブログでJRの運行情報を取得した話を書いた時に「30秒に1度は病的なアクセス頻度」と言われたことがある。クローラーを避けたい管理者はキャッシュを正しく扱ってください。クローラーは違法行為でも攻撃でもありません。「Last-modified-since/ If-none-match」に正しく応答してください。HTTPのキャッシュすら扱えないSI'erはWEB案件にくんな。毎分クローラーを走らせたくらいで攻撃だとメール送ってくる関西電力あんたのことだ。おっと。

ユーザーエージェントを変更する

いくつかのサイトは、ユーザーエージェントによる識別をしているので、私のブラウザの代理をcurl にやらせるので、ユーザーエージェントをブラウザに合わせておく

curl --user-agent "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/48.0.2564.48 Safari/537.36" http://www.yahoo.co.jp/

ブラウザのリクエストをCurlでやる

curl にはいろいろと便利な機能があります。 基本的にhttp リクエストは curl で作成できます。

例えば、ブラウザのリクエストと全く同じリクエストを再現するにはChromeの開発ツールでcURLとしてコピーすればとても簡単です。

f:id:takuya_1st:20151225211705p:plain:w500

chrome からコピーしてきてシェルに貼り付け

ChromeからcURL コマンドとしてコピーしてシェルに貼り付けたら「簡単に」リクエストを再現できる。

Cookieやヘッダもそのまま埋まってくるので、スクレーパー作る時は、Chromeのコピーから始めると便利。

curlCookieの取り扱い

curlcookieを永続したいです。

WEBページにアクセスするにはほとんどの場合、Cookieによって識別されます。

cookie 保存には -c オプション

curl -c ${保存したいパス} http://www.yahoo.co.jp

Cookieの再利用 には -b オプション

curl -b ${保存済みパス} http://auctions.yahoo.co.jp/

Cookieを前回のセッションから再利用しつつ、次回のために保存

curl -b  path -c path  http://auctions.yahoo.co.jp/

オプションの -b -c を同時に使います。ファイル名は同じで構いません

注意:path に同じものを記述するかといって省略することはできません。

curl -bc path  http://auctions.yahoo.co.jp/ ## これはできない。Cookie使えない

これで、Cookieの問題を気にせずに扱えるようになります。

期限なしのセッションクッキーも保存されます。

オプション -c を使えばsession-cookie も問題なく保存されます。

もし保存したくない時は -j をつけてください。

注意:期限なしとは期限の設定がされてないCookieのことです。「期限なし」を長期間Cookie(通称:永続Cookie)と勘違いしそうですが、期限設定なし=セッションCookie=ページを閉じるまで有効=Windowを閉じるまでです。(=タブを閉じただけでは消えない)

Cookieをどこから取り出すのか。

でも、Form送信してCookie作るのめんどくさい。

Cookieは前述のChrome開発ツールの右クリックから取り出すほか、Chromeのユーザープロファイルから取り出すこととができます。

わたしはChromeからコマンドで取り出すことが多いです。

https://github.com/takuya/chrome-storage

chrome-cookie .yahoo.co.jp | jq .

本題のスクレイピングです。

さてさて、それでは準備も整ったしスクレイピングを始めていきたいと思います。

ここまでで

という武器を一通り揃えました。

スクレイピングするときにもう一つ不可欠な武器があります。それがlibxmlです。

最後の武器 libxml

スクレイピングをする時に欠かせない最終兵器がlibxml です。

libxml に添付のxpath 用コマンドでページ要素を取得

grep では絶対に足りなくなるので、 libxml でXMLを解析が必要です。

HTML も XML として解釈してもらえるのでlibxml はスクレイピングには欠かせない。

ruby nokogiri や python lxml なんかそうですね。

libxml はコマンドからも使えるのです。

 libxmlのxmllintコマンドでxpath を実行する

xmllint コマンドではxpath を実行できます。便利!

xmllint --xpath "//nodename" sample.xml

インストール

sudo apt install libxml2-utils

xmllint コマンドでhtml を扱う

xmllint で html を扱うにはhtml オプションをつけます

xmllint --html --xpath "//head/title" sample.html

タイプ量が面倒なので xpath でalias しておきます。

alias xpath="xmllint --html --xpath 2>/dev/null"

エラーメッセージのゴミ箱行きは、まぁ説明のためです。 xpath の基本構文はあとで詳しく書くとして、xpath でどんどんページを取っていきます。

xpathcurl コマンドと組み合わせて戦います。

curl -s  'http://www.yahoo.co.jp/'  |  xpath "//head/title"  - 

3つの武器が揃った

スクレイピングに欠かせない、3種の神器をcurl + libxml で整えました。

処理 コマンド  
ファイル取得 curl  
cookie 取り扱い curl -b path -c path
HTML 解析 xmllint --html --xpath

それではスクレイピング処理をします。

前置き長すぎ。疲れた。

連続ページ取得をしていきたいと思います。

例えば、yahoo オークションの検索結果ページからリンクを全て抜き出すには

curl -s -L  http://j.mp/1YC5mSM | xpath   "//h3/a/@href"  -

この結果それぞれに対して、ページの詳細を取得して保存する。

curl -s -L  http://j.mp/1YC5mSM | xpath   "//h3/a/@href"  -
さらにxargs で展開して

取得したhref の一覧を、さらにxargs で展開して詳細ページにアクセスします。

curl -s -L  http://j.mp/1YC5mSM |xpath   "//h3/a/@href"  -  ¥
| sed 's/href=//g'¥
| sed 's/"//g'  |¥
xargs -P0  -d ' ' -I@  curl -v  -O -L @
間に挟まるsed が邪魔なので

自作のxpath 関数に書き変えます。

git clone git@gist.github.com:894c5aeabc620344bcea.git
cd 894c5aeabc620344bcea
cp xpath /usr/local/bin/
chmod +x /usr/local/bin/xpath
さらに省略化
curl -s -L  http://j.mp/1YC5mSM | xpath "//h3/a/@href"  | xpath "//h1/text()"

xpathcurl の組み合わせでそこそこ戦える。

curlxpath ぱぱっとデータ取得

anemone つかえって話なんだろうけど。

selenium ドライバ使えばいいんだろうけど。

ページの解析もシェルでてきた方がタイプ量少なくて便利だよね!!!

もう少し続くんじゃ。

続き→curl+xpath から始めるお手軽スクレイピング(2) - それマグで!

関連資料

grep でマッチした部分だけを取り出す http://takuya-1st.hatenablog.jp/entry/20121112/1352750670

xpath コマンド http://takuya-1st.hatenablog.jp/entry/2014/08/24/031832

2021-11-28

apt install libxml2-utils を追記

openssl の暗号化と同等のrubyでの処理

openssl で暗号化すると便利なんだけど

暗号化をおこなったデータをそのままプログラムを経由して読みたいよね。やっぱり。

openssl で暗号化 → ruby で復号化

openssl enc -e  -aes-256-cbc -salt -in test.json -out enc.json -pass password:my_pass

これで暗号化したファイルを、rubyでデコードしてみる

      passphrase = "my_pass"
      data = open("enc.json", "r").read
      data = data.force_encoding("ASCII-8BIT")
      salt = data[8,8]
      data = data[16, data.size]
      cipher = OpenSSL::Cipher::Cipher.new("AES-256-CBC")
      cipher.decrypt
      cipher.pkcs5_keyivgen(passphrase, salt, 1 )
      data = cipher.update(data) + cipher.final
      open("out.json", "w"){|f| f.write data }

ruby で暗号化 → openssl で復号化

ruby で暗号化したものを openssl で復号化する。

      passphrase = "秘密秘密"
      data = open("plain.json", "r").read
      cipher = OpenSSL::Cipher::Cipher.new("AES-256-CBC")
      salt = OpenSSL::Random.random_bytes(8)
      cipher.encrypt
      cipher.pkcs5_keyivgen(passphrase, salt, 1 )
      data = cipher.update(data) + cipher.final
      ## salted
      data = "Salted__" + salt + data
      open("enc.json", "w"){|f| f.write data }

openssl で復号化

openssl enc -d  -aes-256-cbc -salt -in enc.json -out plain.json -pass password:秘密秘密

OpenSSLで簡単にファイルを暗号化・復号化する(コマンド一発)

openssl コマンドでファイルを暗号化します。

ファイルを暗号化してパスワードをつけたい場合、一番お手軽なのはWindowsExcelのパスワードですが、 一般のファイルで、ファイルにパスワードをつけたい場合は、opensslをコマンドから使うのが手軽です。

openssl コマンドでファイルを容易く暗号化出来る

ファイルを暗号化するには、とてもシンプルにopenssl を使うのが楽ですよね

ファイルの暗号化

次の例では、ファイル(test.json)を暗号化しています。 ここでは、パスワード($PLAIN_TEXT_PASS)を鍵として使います。

openssl enc -e  -aes-256-cbc -salt -pbkdf2 -pass pass:$PLAIN_TEXT_PASS -in test.json  -out test.json.enc

ファイルの復号化

次の例では、ファイル(test.json)を復号化しています。

openssl enc -d  -aes-256-cbc -salt -pbkdf2 -pass pass:$PLAIN_TEXT_PASS -in test.json.enc -out test.json

openssl enc を使う

ファイルをAESで暗号化するには enc を使う。

openssl enc  オプション

じつは、openssl はサブコマンド方式なので、次のようになっています。enc はサブコマンドの一つです。

openssl サブコマンド オプション

オプションの解説

引数 意味
enc 対象鍵(パスフレーズ)で暗号化・復号化
-e 暗号化処理を指定
-d 復号化処理を指定
-salt slatを使うことでバイナリからの憶測を困難に
-pass パスフレーズをどこから取るか (指定なしはプロンプト )

パスフレーズの与え方

  • pass:password プレインテキストで直書く
  • env:var 環境変数から
  • file:pathname ファイルから
  • fd:number ファイルディスクリプタから
  • stdin 標準入力から
パスフレーズの与え方の例

よく使いそうなのは次の3つでしょうね。

プレインテキストで

openssl enc -e  -aes-256-cbc -salt -pass pass:秘密秘密

環境変数から

export my_pass=秘密秘密
openssl enc -e  -aes-256-cbc -salt -pass env:my_pass

ファイルから

echo  秘密秘密 > my_pass_file
openssl enc -e  -aes-256-cbc -salt -pass file:my_pass_file

詳しくは、openssl のPASSWORD ARGUMENTSの章を参考にすること

2018-11-26

検索キーワードにうまくマッチしないのでエントリ書き換え、。

2020-12-16

openssl が -pbkdf2 をつけないと deprecated というので追加した。

参考資料

  • man enc
  • man openssl

みんな大好き!man ページ

download-pdf

download-pdf

クレジットカードの入力を実現する簡単なブックマークレット

クレジットカードの番号の入力がめんどくさい

クレジットカード番号を入力が4つの「Input」に分割されててイライラしませんか?私はイライラします。

4回もコピーしなおしとかちょっと無理

f:id:takuya_1st:20151208173502p:plain

作った

作った作った。面倒なことは自動化する。

ブックマークに登録(動作サンプル)

- - -

クレジットカードカンタン入力

iterateNext()で

input 書き換えながらiterateNextするとエラーになった。 xpath で検索した結果を使うときは動的にノードの状態が変わるとダメなようだ・・・不便ね。

Uncaught DOMException: Failed to execute 'iterateNext' on 'XPathResult': The document has mutated since the result was returned.

2019-07-06 更新 2019-08-21 更に更新

.//input だと取れすぎるので、Xpathを修正する。

(function() {
    card = []
    card_number = window.prompt("カードナンバー?", "");
    if (card_number.length == 16) {
        card_chars = card_number.split("")
        card.push(card_chars.slice(0, 4).join(""))
        card.push(card_chars.slice(4, 8).join(""))
        card.push(card_chars.slice(8, 12).join(""))
        card.push(card_chars.slice(12, 16).join(""))
    } else if (card_number.length == 19) {
        card = card_number.split("-")
    }
    card_input = []
    var xpath = '//*[count(./input[@type="text"])>=4]//input '
    +' | //*[count(.//input[@maxlength=4])=4]//input'
    +' | //*[count(.//input[@size=4])=4]//input'
    +' | //*[count(./input[contains(translate(./@name,"ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"card") and @type="text" ])>=4]/input'
    +' | //*[count(./input[contains(translate(./@id,  "ABCDEFGHIJKLMNOPQRSTUVWXYZ","abcdefghijklmnopqrstuvwxyz"),"card") and @type="text" ])>=4]/input'
    /*ret = document.evaluate("//*[ count(./input) = 4 ]//input", document)*/
    ret = document.evaluate(xpath, document)
    
    while ((input = ret.iterateNext())) {
        card_input.push(input)
    }
    card.forEach( (e,i) => {
      card_input[i].value = card[i]
    });
})()

bashでファイルがリンクかどうか調べる

このファイルがリンクかどうか調べるには

if  [  -f /usr/local/bin/ruby -a  -L /usr/local/bin/ruby ] ; then
  echo "link exists"
else
 echo "not link"
fi

Bashの比較オプション

オプション 意味
-f ファイルかどうか調べる
-L シンボリックリンクかどうか調べる

リンクかどうか調べるには、ファイルの存在を調べたうえで、リンク状態を調べる

ファイルの存在は必須ではないかもしれない。でもリンクかどうか調べるときはリンクを取得したい、リンクを作成したいの場合がほとんどなのでファイルの存在を調べないとはまる。

参考資料

http://tldp.org/LDP/abs/html/fto.html

nokogiriがインストール出来ないとかいう定番のアレ Mac OSX 10.11.1

nokogiri のインストールに失敗するというミス

これが有名なNokogiri地獄だ!まさか自分がハマるとは思わなかったですね。

Nokogiriとかいう多くのRubyGems ライブラリで使われるものがインストール出来なくて詰むという。

とっても悲しい事象が発生しました。

rails, mechanize → nokogiri 依存 → mini_portile2 依存 で詰む。何処でコケたか考えることすら面倒な感じです

解決方法は「ググらない?」

ググッても、「私はコレでできました」「ウチではこのコンパイルオプションで動きました」とか皆行ってることがバラバラなんですね。nokogiri のインストール出来ませんのブログも、 homebrew も rbenv も入ってるのか、Xcodeのバージョンも記載が無かったり闇を感じる。2時間ほど検索して時間を無駄にした。来年OSX 10.12(OSXi 11 )の自分のためにメモっておく。

nokogiriのインストールは

今日のnokogiriはいくつか改善されている。

OSX の標準添付のruby ( /usr/bin/ruby ) を使う限りでは、次の通りで簡単にインストール出来る

sudo /usr/bin/gem install nokogiri -- --use-system-libararies

若しくはinstall_dir を指定して自分のgem環境にnokogiriを入れられる。

mkdir ~/.lib/ruby
/usr/bin/gem install --install-dir ~/.lib/gems nokogiri -- --use-system-libararies

随分と楽になったね。でも私は、homebre+rbenv+ruby-build環境なんだ。

OSX にnokogiriを入れなおしたのでメモを取る。

  • 環境の確認
  • homebrew の確認
  • rbenv の確認
  • 環境をOSX標準に近づける
  • libxml2 の確認
  • rbenv で新規環境
  • nokogiri インストール

この順番で処理をしていった。

OSXの環境の確認

まずはじめに、OSXの環境の確認。今の私のOSXは最新バージョンに自動アップデートされている。

takuya@~/Desktop$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.11.1
BuildVersion:   15B42

ビルド環境の確認

次にビルド環境の確認をしておく。

takuya@~/Desktop$ brew --config
HOMEBREW_VERSION: 0.9.5
ORIGIN: https://github.com/Homebrew/homebrew.git
HEAD: ae6c42c7eacf5196e83098658b795c883b9d9a87
Last commit: 9 hours ago
HOMEBREW_PREFIX: /usr/local
HOMEBREW_REPOSITORY: /usr/local
HOMEBREW_CELLAR: /usr/local/Cellar
HOMEBREW_BOTTLE_DOMAIN: https://homebrew.bintray.com
CPU: quad-core 64-bit haswell
OS X: 10.11.1-x86_64
Xcode: 7.1.1
CLT: N/A
Clang: 7.0 build 700
X11: 2.7.8 => /opt/X11
System Ruby: 2.0.0-p645
Perl: /usr/bin/perl
Python: /usr/local/bin/python => /usr/local/Cellar/python/2.7.9/Frameworks/Python.framework/Versions/2.7/bin/python2.7
Ruby: /usr/bin/ruby => /System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/bin/ruby
Java: 1.8.0_31, 1.8.0_25, 1.7.0_75, 1.6.0_65-b14-468

Xcode が7.11 ですねー

大好きなgccがなくてLLVMです。

rbenv の確認

念のためrbenvも確認しておきます。

takuya@~/Desktop$ rbenv --version
rbenv 0.4.0
-環境をOSX標準に近づける

nokogiriのメンテナーがコンパイルチェックしてるだろう標準環境に戻します。

OSXの標準のつもりな私の環境も、もしかしたらおかしくなってるかもしれない。

brew の一旦退避する。

homebrew や rbenv が入ってると、ミスがわからないので全部を片付けておきます。後で戻すけど

brew list | xargs -P5 -I@ brew unlink @

これで /usr/local/{bin,lib,include,opt} をほぼ空っぽにしてしてく。

brew コマンドだけ必要であとはいらない。

さらに、念のため、独自設定だらけのbashrcも退避しておいた。

私の場合、bashrcに.gemsフォルダ参照や、alias rubyだのrbenv ショートカット設定だのが多く入ってるので邪魔になりました。普通はやらないでいいとおもう。

mv ~/.bashrc ~/.bashrc.bak
さらに、ログインシェルを標準/bin/bashにする。

zsh や /usr/local/bin/bashを使ってると切り分けが面倒なので、出来る限り初期のクリーン・インストール済み環境に近づけた。

f:id:takuya_1st:20151207110034p:plain:w300

で、ほぼ素のbashでターミナルを起動しておく。

ここままでで、最低限必要な物だけを戻しておく

brew link ruby-build rbenv
無い
  • /usr/local/bin/{bin,lib} | brew unlink でbrew 関係はすべてリンクから消した
  • ~/.gems | bashrcを無効にして、gem ,ruby_lib もまっさらに
  • ~/.rbenv | こちらも退避した
ある
  • /usr/local/bin/brew
  • /usr/local/bin/rbenv
  • /usr/local/bin/ruby-build

最低限を残しbrewもほぼ初期状態。

面倒だったら新規ユーザーでどうぞ

無味乾燥な環境を作った

f:id:takuya_1st:20151207110103p:plain:w300

ほぼ素の状態のbashでターミナルを使うことにした。これで余計なことに神経を使わなくて済む。

おもむろに、nokogiri (system-ruby)の ビルドを試してみる。

ほぼ、素の状態なのでOSXのsystem ruby で nokogiriを入れてみる

gem install だけだとPermission エラーになるので自分のホームディレクトリにコンパイルして格納

gem install   nokogiri --install-dir ~/.lib/gems  --verbose -- --use-system-libaries

これで、まず問題なく動くことがわかる。

余計なものは一切ない。nokogiriの製作者が意図した環境でメンテナーがテストした環境になってると思う。

とりあえず、rbenvを作ってみる。

私の環境ではrbenvもコケてたので入れなおしてみる。 2.2.x 系はすでに動いているので、とりあえず2.1.x系で実験

RUBY_BUILD_CACHE_PATH=/tmp rbenv install -v 2.1.7
(ry
Installed ruby-2.1.7 to /Users/takuya/.rbenv/versions/2.1.7

無事インストールが動き出した。

brew のリンクを元に戻す

ここままでで、環境の確認が出来たので、おもむろにbrew linkを戻して環境を整理しておく。

brew list | xargs -P5 -I@ brew link @
libxml系をリンクする

あとで必要になるので、libxml2 の最新版を入れておく

brew install libxml2 libxslt 
brew --force libxml2 libxslt 
libxmlのバージョン確認

libxml2 をリンクした状態でバージョン確認をしたらこんな感じ

takuya@~$ xml2-config --version
2.9.2
takuya@~$ xslt-config --version
1.1.28
takuya@~$ which xml2-config
/usr/bin/xml2-config
takuya@~$ which xslt-config
/usr/bin/xslt-config

最新版の nokogiri 1.6.7 で必要になるみたい

rbenv を作る

rbenv をターゲット環境で作ってみる。

RUBY_BUILD_CACHE_PATH=/tmp rbenv install -v 2.2.3
(ry
Installed ruby-2.1.7 to /Users/takuya/.rbenv/versions/2.2.3

で、rbenv 経由で ruby 2.2.3 を有効に

rbenv global 2.2.3 
nokogiri (rbenv 2.2.3)をインストールしてみる。

で、やっとここまで到達。ruby 2.2.3 (rbenv) に nokogiri 1.6.7 を入れる

gem install nokogiri --verbose -- --with-xml2-dir=`brew --prefix libxml2` --with-xslt-dir=`brew --prefix libxslt`
(ry
/Users/takuya/.rbenv/versions/2.2.3/bin/nokogiri
Successfully installed nokogiri-1.6.7
Parsing documentation for nokogiri-1.6.7
Parsing sources...
100% [179/179]  suppressions/README.txt
Done installing documentation for nokogiri after 3 seconds
1 gem installed

お疲れ様でした!!!!

takuya@~$ rbenv exec nokogiri -v
# Nokogiri (1.6.7)
    ---
    warnings: []
    nokogiri: 1.6.7
    ruby:
      version: 2.2.3
      platform: x86_64-darwin15
      description: ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-darwin15]
      engine: ruby
    libxml:
      binding: extension
      source: packaged
      libxml2_path: "/Users/takuya/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/nokogiri-1.6.7/ports/x86_64-apple-darwin15.0.0/libxml2/2.9.2"
      libxslt_path: "/Users/takuya/.rbenv/versions/2.2.3/lib/ruby/gems/2.2.0/gems/nokogiri-1.6.7/ports/x86_64-apple-darwin15.0.0/libxslt/1.1.28"
      libxml2_patches:
      - 0001-Revert-Missing-initialization-for-the-catalog-module.patch
      - 0002-Fix-missing-entities-after-CVE-2014-3660-fix.patch
      - 0003-Stop-parsing-on-entities-boundaries-errors.patch
      - 0004-Cleanup-conditional-section-error-handling.patch
      - 0005-CVE-2015-1819-Enforce-the-reader-to-run-in-constant-.patch
      - 0006-Another-variation-of-overflow-in-Conditional-section.patch
      - 0007-Fix-an-error-in-previous-Conditional-section-patch.patch
      - 0008-CVE-2015-8035-Fix-XZ-compression-support-loop.patch
      - 0009-Updated-config.guess.patch
      - 0010-Fix-parsering-short-unclosed-comment-uninitialized-access.patch
      libxslt_patches:
      - 0001-Adding-doc-update-related-to-1.1.28.patch
      - 0002-Fix-a-couple-of-places-where-f-printf-parameters-wer.patch
      - 0003-Initialize-pseudo-random-number-generator-with-curre.patch
      - 0004-EXSLT-function-str-replace-is-broken-as-is.patch
      - 0006-Fix-str-padding-to-work-with-UTF-8-strings.patch
      - 0007-Separate-function-for-predicate-matching-in-patterns.patch
      - 0008-Fix-direct-pattern-matching.patch
      - 0009-Fix-certain-patterns-with-predicates.patch
      - 0010-Fix-handling-of-UTF-8-strings-in-EXSLT-crypto-module.patch
      - 0013-Memory-leak-in-xsltCompileIdKeyPattern-error-path.patch
      - 0014-Fix-for-bug-436589.patch
      - 0015-Fix-mkdir-for-mingw.patch
      - 0016-Fix-for-type-confusion-in-preprocessing-attributes.patch
      - 0017-Updated-config.guess.patch
      compiled: 2.9.2
      loaded: 2.9.2
じゃ、bundle も行ってみよう
echo gem "mechanize" , "=2.7.3" >> Gemfile
bundle install 

出来た

疲れた・・・

少し疲れました。

とりあえず、Nokogiriがインストール出来ないとかいう定番のアレは、brewgcc 関連やgnu コマンド関連がPathに含まれててバッティングしていたということが分かった。

bundle するときは bundle config を使うといい。

いまのnokogiriをインストールしてみた感じだと、殆どの人は bundle install でコケることはないんだろうな。

bundle exec gem  install nokogiri 

または、直接ビルドオプションを指定する。

bundle config  build.nokogiri -- --with-xml2-dir=`brew --prefix libxml2` --with-xslt-dir=`brew --prefix libxslt`
bundle install