かれ4

かれこれ4個目のブログ

HosterをYosemiteで使う

Hoster (RedWinder::MacApp::Hoster) がYosemiteになってInstallできなくなった。

できなくなった原因は、
Contents/distribution.dist
に書かれているVersionチェックの問題。


10.10.x に対して >= '10.4'となっているので、10.10 は10.1扱いで、インストール出来なくなっている。

というわけで、
Contents/distribution.distの7行目のVersionチェックを正規表現でのものに書き換えてあげれば、Yosemiteでも無事にインストール出来る。

-  if(!(my.target.systemVersion.ProductVersion >= '10.4')) {
+  if((my.target.systemVersion.ProductVersion+'').match(/10.[1-3]\./)) {

株式会社マイニングブラウニーは2015年1月1日から株式会社オークファンの子会社になりました。

あけましておめでとうございます。

タイトルの通りなのですが私のやっていた会社、株式会社マイニングブラウニーは2015年1月1日から株式会社オークファンの100%子会社となりました。

プレスリリース

自分の作った会社だったので、退職とはちょっと違いますが、一つの区切りとして、書いておきたいと思いました。


とりあえず恒例のほしい物リストを

http://www.amazon.co.jp/gp/registry/wishlist/3AYKVKHE1C52X



経緯

この話をしはじめたのは、そんなに前の事ではありませんでした。

資金調達を考えて、証券会社の人とお話をしたら、その数分後にオークファンの武永社長から情報交換でもどうですか?というお話が直接ありました。

証券会社の仕事が早すぎるなと思っていたら、本当に偶然声をかけてくれたようです。

今後3年間で私がやりたい事をお話し、オークファンの今後やっていこうとしていることをお聞きしました。
その中で、やろうとしていることが非常に重なっている部分が多く少しワクワクしたのを覚えています。

それからの数ヶ月間は色々悩みながらも、何人かのオークファンのメンバーともお話していく中で徐々に期待に変わっていきました。


2014年に何を考えていたのか

話は少し戻って、2014年という1年に何を考えていたのか。

株式会社マイニングブラウニーという会社は前身の米国法人も含めると9年3ヶ月やっていたわけですが、
その間データをいかに有効に使っていくのかというのを考えてきました。

考えた中で、自分の中でしっくりきた考えかたとして、幾つかのフェーズによって分類し、キチンと回転させる事が大切だと考えてました。

この円はデータの活用において必要なフェーズを6つに分けたものです。

f:id:tottokug:20150102001447p:plain

今までデータを扱うのに指標がなかったため、ビッグデータという言葉がひとり歩きし、
うまく活用できていない企業を見てきました。
データがなかったり、整理できていなかったり、分析できていなかったり。

そんな中、2014年にはビッグデータが幻滅期に入り、やっと過度な期待がなくなり正当な評価をしだしたと感じ始めました。


先進テクノロジのハイプ・サイクル: 2014年

f:id:tottokug:20150101214341g:plain

出典: ガートナー (2014年8月)

2015年にはこのチャンスを活かしたいと思っていました。
そこで資金調達を考えはじめたのです。

ここで冒頭の証券会社との話になります。


ビッグデータへの幻滅と同じくして、IoTが騒がれるようになってきました。
正直なところ私はそんなにIoTには興味がないのですが、IoTによってビッグデータが早期に幻滅期を抜ける可能性があることに期待しています。
それはIoTによって莫大な量のデータが手に入るようになり、機械的に処理する必要が出てくる事になってくるそんな時代が見えたからです。

今後3年間で可視化、活用する部分を強化していくことも考えましたが、その場合どうしてもスピード感が足りないと感じていました。
であれば、分析の部分にリソースを集中しようと。


そこでデータの分析について調べ、考えました。

分析について

いわゆる分析と言っても、いくつかの段階に別れます。

f:id:tottokug:20150102095210p:plain

今の段階では、私は

  • Reporting
  • Analysis
  • Monitoring
  • Prediction

この4段階に分けたいと思います。
今後、ルールを決めるとかそういったことが分析の中に組み込まれていくような気がします。


Reporting

まずもっとも簡単で価値を得られるものとして、データから過去を知る事です。
過去を知ると言うのは何が起こったかを知ることです。
例えば、飲食店であれば、12時には食事がよく出るけど、15時にはコーヒーが良くでる。といったことがわかります。
たいてい現場の人間からすると知ってたというようなものがほとんどだったりします。

先ほどの6つのフェーズでいうと、分析というよりもどちらかと言うと整理と可視化に近いです。

Analysis

次に、過去に起こったことの理由を知ることです。
飲食店でいうと、12時はランチの時間だし、15時はティータイムという理由付けになります。

いわゆるBIと呼ばれる領域では、この過去に起こったことの理由を探るのに、
人間の外部知識が必要だったりします。
これを機械がやろうとすると、途端に難しくなります。
レジのデータだけでなく、別のデータが必要になってくる可能性もあります。

Monitoring

モニタリングなんて、さっきの理由を知ることに比べたら簡単じゃないかと思われるかもしれませんが、
ここでいうモニタリングと言うのは、リアルタイムに物事を知ることにとどまらないと考えます。

例えば、クレジットカードを利用した時に、その利用が不正なのか、不正ではないのか
そういったことを検知してこそのMonitoringです。
リアルタイムで人間が見ることを求めていません。リアルタイムで、機械が判断することを求めます。
ここに来ると、確実に機械学習が必要になります。

Prediction

最後にPrediction。未来の予測です。
飲食店でいうと客足予測、注文予測などがこの領域に入ってきます。
機械学習だけでなく、人工知能の他の研究範囲の技術も必要になって来ることもありますが、2015年以降はここに力を入れていきます。

2015年以降

前述のとおり、マイニングブラウニーとしてこれからPredictionに力を入れていきたいと思っていたところ、オークファンの今後の計画とぴったりとフィットし、一緒にやっていきたいという気持ちになりました。

ちなみに、オークファンの考えるデータの活用に関しての図はプレスリリースに載っている画像の通りで、
f:id:tottokug:20150102105049j:plain

  • Data
  • Infomation
  • Presentation
  • Solution

の4つに分類しています。
これを先ほどの6つのフェーズに重ねると以下の図のようになります。

f:id:tottokug:20150102110153p:plain

そして、オークファンは既にaucfanや、valuefanといったPresentationを展開しています。
また、Solutionについても、力をいれています。

マイニングブラウニーは創業時から要素技術でやっていくと決めていたので、DataとInfomationをサービスとして展開しています。
私はオークファンでDataとInfomationの部分を担当します。

今回の子会社化により、4つの領域すべてに力を入れられることになります。
この4つの領域が噛み合ってビジネスを展開出来る今、数年後が楽しみで仕方ありません。



さいごに

今回の子会社化にあたって、たくさんの人の協力がありました。
また、マイニングブラウニーという会社も私自身も9年間の間で沢山の人と知り合い、色々なことを経験させてもらったお陰で、今回のようなタッグが実現したと思います。
この場にてお礼を申し上げたいと思います。

これからもオークファンとしての私もよろしくお願い致します。

人間にはわかるのに、なぜ機械にはそれがわからないのか。A.I.とスクレイピング

この投稿は クローラー/スクレイピング Advent Calendar 2014の12月23日用です。


はじめに

人間って凄い。

まずはこの画像を御覧ください。

f:id:tottokug:20141223133132j:plain

図1 各国のECサイトの画像

Eコマースのサイトで、商品の詳細のページを見るだけですぐに商品名、価格を判断出来ましたよね?
それが英語のサイトでも中国語のサイトでも、韓国語のページでも分かりましたよね?
凄いですね。

人間のスクレイピング能力

人間は恐ろしいほどのスクレイピング能力を持っている事が分かりました。
ソースも見ない、タグも見ないで、なんとなく雰囲気だけでスクレイピングしています。

もしこの能力をコンピュータに移植できたら凄いことですね。


もし、先ほどの画像を身の回りのインターネットに一番疎い人に見せてみて下さい。
きちんとスクレイピング出来たでしょうか?
おそらく出来なかった事が多いのではないかと思います。

こんな事させて何させたいかと、人間のスクレイピング能力は生まれつき持っているものではなく、なんらかの学習のプロセスを経て手に入れたものだということです。

それも、人生における経験ではなく、インターネットに関する経験です。

この経験をもしコンピュータで実現出来たら、スクレイピングの自動化に近づくはずです。

なぜやろうとしたのか

もともと家電やPCの価格調査を行っていました。
そこから本業としてクローラのプラットフォームを作りました。
抽象化するべきところは抽象化し、プラットフォームとすることが出来たのですが、それはスクレイピングの運用の手間を極力減らすためのものであって、スクレイピングまで自動化するものではありませんでした。

例えば、Eコマース 100サイトから価格情報を収集したいとします。
その場合、100サイト分のスクレイピング用のコードを用意しなくてはいけません。
抽象化したところで、100サイト分の何かしらが必要になります。
これが決まった100サイトとわかっていれば、頑張れるかもしれません。
しかし、100サイトから増減していった時、ずっと対処し続けないといけません。
運用のコストばかり上がってしまい、疲弊していく事は目に見えてます。

この状況を打破するために、人間と同じような成長をし見分ける能力をコンピュータ上に作りたいと思いました。

どのようにやるか

人間がなぜスクレイピング出来るのかを真剣に考えました。

人間がスクレイピングしている時はどのように判断していくのか仮説を立てました。

  • 周辺にある単語から判断
  • 位置関係からの判断
  • 文字の大きさからの判断
  • 文字の色からの判断

この4つから判断しているだろうと考え、この4つを学習させるすべを考えます。
しかし、これには問題があります。

f:id:tottokug:20141223135450p:plain
画像2 レコメンドなどで複数の商品が同じページ内に載っている場合

このような場合、複数の抽出すべき項目があり、悩ましいです。

そこで、HTMLを分割することにします。

HTMLからブロックを抽出する

HTMLからブロックを抽出する方法ですが、これはDOMツリーを必要最小の範囲で抜き出すと言い換えられます。

f:id:tottokug:20141223170423p:plain
図3 全体のDOMツリーから、必要部分の抽出

では、これをどのように実装していくかという話になります。
大きくは、

  • タグに対してのスコアリング
  • スコアによるフラグ付
  • フラグの付いているタグをマージ

の3つの工程になります。

サイトの性質毎に特定の言葉(ECであれば税込や送料など)の存在に応じて、
全てのタグに点数をつけていきます。点数の付け方は、そこに含まれる単語とタグの深さを計算してつけていきます。
点数をタグの開いた順番に並べ、微分していきます。
微分した値にしきい値を設け、ブロックを構成する部品としてフラグを立てて置きます。
可視化すると先ほどの図2のようなページの場合は以下のようになります。
青がタグの深さ、緑がタグに付けられたスコア、ピンク色がフラグです。
可視化するとこんな感じになります。
f:id:tottokug:20141223155743p:plain
図4 タグのスコアリング

真ん中よりも少し左側にフラグが幾つか立っている所があります。
ここがメインの商品の情報になっています。
そして、真ん中から右側に周期的にフラグが現れている所がありますが、これがレコメンドによって表示されている商品です。

次はこれをブロックとしてまとめ上げる工程に入ります。
ここから先はHTMLをツリー構造と見た解析になっていくので、タグの事をノードと呼んで行きます。

バラバラと存在しているフラグ付されたノードをまとめる作業になるのですが、
親のノードからみて、子孫たちがどの程度フラグが立っているかというのを見ていきます。
もし、自ノードの配下のノードでフラグ付されているノードの数が多い場合は自分自身がフラグ付されて行きます。
この工程を何度か繰り返す事によって、ブロックを抜出します。

以下の図で説明すると、まずはピンク色がフラグ付されたノードになります。
フラグ付されたノードが子供の中に割合多くいた場合自分自身がフラグ付されるというルールに基づき、再度フラグ付されます(赤いノード)
全く同じルールにもとづいてルートノードから辿って行くことで、今度は青いノードが生まれます。

f:id:tottokug:20141223161415p:plain

f:id:tottokug:20141223161418p:plain

図5 フラグから必要最小の範囲の決定

このような工程を何度か繰り替えす事によって、抽出すべきブロックが導きだされます。
この工程は複数回やっても、あるところに集約されますが、だいたい一般的なHTMLの深さであれば、5回もやれば十分集約されます。

これでブロックが抽出出来ました。

ブロックから項目を抽出する

つぎにこのブロックから項目を抽出していきます。
抽出するためにはどのようにするのが良いのでしょう。

ここに機械学習的なアプローチを使っていきます。

この処理に入る段階で既に、ブロックとなっているため、ページ全体のノードの数に比べだいぶ少なくなっています。
だいたい20〜50位のノード位になっています。

これらのノードそれぞれで取得したい項目、例えば"商品名"や"価格"などに対してのそれぞれの尤度を求めて行きます。

下の図の青いノードが商品名かどうかを調べる場合を考えてみます。
青いノードの自己主張だけでは、怪しいので、ピンクのノードの意見も取り入れます。
ピンクのノードは青のノードの位置関係と、含まれる単語、タグ名、アトリビュートから青いノードが商品名のノードであるかどうかを主張します。
f:id:tottokug:20141223162939p:plain
図6 ノードが商品名らしいかの投票

ピンクのノードが満場一致で、この青いノードが商品名ですというのであれば良いのですが、そんな事はありません。
なので、ピンクのノードのみんなの意見を集約して、青いノードが商品名だと判断をしていきます。
こんな判断を全てのノードに対して行い、得票数が一番多いノード、かつ閾値を超えているものを商品名として判断します。

しかしこれだけだとピンクのノード全てが同じ重みで判断されてしまいますが、そんなことはないはずです。
なので、各タグに対しての重みの係数を与える事にします。
そして、この係数の調整は、遺伝的アルゴリズムを使って自動的に調整されるようにします。


この仕組によって、ノードが商品名であるのかどうかを判断し、抽出します。
スクレイピングの自動化が出来ました。


この仕組の現在とこれから

この仕組みは 特許を取得しています。
特許 第4959032号(2012年3月30日)

そして、サービスとしても提供しています。 hanamgri

しかし、β版リリースから数年たっても未だにβになっています。というのも、今は教師付きの学習が必要ですぐに使えるようなものではないからです。
今後Deep Learningでの特徴の発見が自動的に出来るようになれば、ユーザによる事前の学習を必要とせずに利用できると考えています。

ちょっと小難しい話になってしまいましたが、スクレイピングを機械にやらせようと思い、考えた仕組みの紹介でした。

HTMLパーサとしてのwkhtmltoimage。js実行後のDOMが取れるよ。

クローラー/スクレイピング Advent Calendar 2014の12月20日です。

タイトルに書いてあることが全てではありますが、いちおうスクレイピングするにあたっての事を。

スクレイピングする時のアプローチとして、大きく2つあると思います。
1つは、完全にテキストとして正規表現で抜き出してくる方法。
もう一つが、HTMLをパースしてXPathやそれに似た(CSSセレクタ)構文で取得する方法。

今回は後者のパースして取得する方法について書きます。


なぜパースする必要があるのか

世の中のHTMLは汚い。CMSを使っていたとしても汚い。
タグがグチャグチャです。
グチャグチャのタグの構造からXPathで取得しようとすると、思った動作をしないことが多々あります。
なので、一旦パースをして、きちんとした構造を使わないと痛い目を見ることがすくなくありません。

どのパーサを選ぶべきなのか

HTMLのパーサには色々な種類があります。
私は普段Javaでのクローリング・スクレイピングをしているので、Javaのライブラリを良く使うのですが、
今個人で使っているのは主にTagSoupです。
業務で使っているのは、MozillaParserです。
しかし、今業務で使っているMozillaParserをやめて、WebKitをベースにしたものを検討しています。

MozillaParserから、WebKit

なぜWebKitベースのものへと切り替えるのかというと、
WebKitベースは現在 SafariGoogle ChromeOpera等最近のモダンなブラウザの大半が使っていて、表示確認などもおそらくこれらに最適化されているだろうと予測されるからです。
(厳密にはWebKitからForkしたBlinkだったりしますが、、)

WebKitベースのParser

特にWebKitベースのParserがあるわけではないのですが、wkhtmltopdfというライブラリを使用します。
(実際に利用するのはwkhtmltoimageですが)
ただ、このままでは、色々と問題があるので当然、改造することになりますが、LGPLなので安心です。
大きな問題点としては以下の2点が上げられます。

  • 問題点1:GUIのない環境での動作
  • 問題点2;標準ではHTMLの出力では無くグラフィクスでの出力

この2つを解決しないことにはParserとしては使えません。
では、この2つをいかにして解決していくかというところを今回の主題として書いていきます。

まずはGUIのない環境での動作については、これは仮想フレームバッファを利用することで、解決ができます。
これは、JenkinsでJavascriptのテストをしたことがある人であれば、馴染みのあるものだと思います。

GUIのない環境だったとしても、仮想のディスプレイを作り、そこに対して描画するという方法です。


もう一つの問題点、標準ではHTMLの出力をしてくれないという点です。
これはもう改造してしまえば良いだけなので、簡単です。

ただ、改造する為の環境構築がなかなかのクセモノだったりもします。

まずQtが必要です。しかもyumやaptで入るような新しいものではなくて、若干古いものが必要になってきます。
どのバージョンが必要かはwkhtmltopdfのソースリポジトリ(https://github.com/wkhtmltopdf/qt)に記されているので、そちらを利用します。

Qtの準備

Qtの準備とコンパイル環境の構築はここに書いてしまうと、文章ボリュームの大半をしめてしまうので、ここには書きません。


wkhtmltopdfの改造

wkhtmltopdfは現状では、PDFでの出力はできますが、HTMLを出力することはできません。
なので、改造してhtmlを出力できるようにします。
 

改造は ここのソースをベースにしていきます。

改造のポイントは大きく2つで、

  • コマンドラインの引数を処理する部分にHTML出力用のオプションを追加する。
  • オプションに応じてHTMLをファイルに書き出す。

です。

まずオプションを追加するのに

  • src/image/imagearguments.cc
  • src/image/imagecommandlineparser.cc
  • src/image/imagecommandlineparser.hh
  • src/lib/imagesettings.cc
  • src/lib/imagesettings.hh

詳細は省略しますが、この辺りのファイルを編集します。


実際にファイルにHTMLを書き出すための処理を追加するのに、
src/lib/imageconverter.cc
このファイルのImageConverterPrivate::pagesLoadedを変更します。

変更点としてはオプションでHTML出力が指定されていた時に、ファイルに書きだすようにします。

if(settings.ophtml != ""){
  QString html = frame->toHtml();
  QFile file(settings.ophtml);
  if(file.open(QIODevice::WriteOnly)){
    QTextStream outfile(&file);
    if(settings.codec != ""){
      QTextCodec* codec = TextCodec::codecForName(settings.codec.toAscii());
      outfile.setCodec(codec);
    }
    outfile << html;
    file.close();
  }
}

を追加します。

これで、makeしてあげれば、html出力が出来るwkhtmltoimageができます。

$ wkhtmltoimage --output-html yahoo.html http://blog.tottokug.com blog_tottokug_com.png

とすると、http://blog.tottokug.comのhtmlがwebKitでパースされ、Javascriptの実行後のHTMLを取得したい場合は --javascript-delay というオプションでJavascript実行後に指定したミリ秒間の遅延を持って出力されます。

curlwgetで取ってきたhtmlをいきなり使うよりも、きれいな構造になったHTMLを取得する事ができます。

また、JavascriptでHTMLを作っているようなサイトだったとしても、これでクローリング・スクレイピングが可能になります。

副作用として、レンダリングしたものを画像として保存する事も出来ます。

Mac OSX Yosemiteにしてから、メニューバーがよく固まる

Yosemiteにしてからメニューバーが良く固まるし、CPUを良く喰ってる事がある。

時間は進んでるのに、クリックしても無反応みたいな
たぶんDropboxがよろしく無い気もする。

根本的な解決では無いけれど、プロセスの再起動で一旦治る

ps -ax |grep /SystemUIServer | perl -pe "s/^\s*(\d+).*/\1/g" |head -n 1  |xargs kill


コマンドでの操作に慣れていなかったら、Spotlight 検索で
「activi」これくらいまで打つとActivity Monitor.appが引っかかるので、
起動して、"SystemUIServer"を落とす。

oracleのjdkをwgetで落としてくる

## 2017/08/19 追記
jdk 8u144b01からは/jdk/の後に
8u144b01/というようなディレクトリが出来、さらにその下に
090f390dda5b47b9b721c7dfaa008135
というディレクトリが間に入るようになったため、
今までのようにバージョンだけわかっていれば、ダウンロード出来るわけではなくなってしまった。
どうせ,b01とかの部分はURLから調べることになったりすると思うので、
その時に同時に調べれば良いが注意が必要です。

    • -


oracleJDKはライセンスに同意しないと行けないので、wgetでダウンロードするのツライ。
f:id:tottokug:20141127143208p:plain

実際にブラウザでライセンスに同意すると

f:id:tottokug:20141127143103p:plain

cookie

oraclelicense=accept-securebackup-cookie

こんな怪しいやつがいる。
というわけで、このCookieをくっつけて、Downloadしてみる。

$ wget --no-cookies --no-check-certificate --header "Cookie: oraclelicense=accept-securebackup-cookie" "http://download.oracle.com/otn-pub/java/jdk/8u144-b01/090f390dda5b47b9b721c7dfaa008135/jdk-8u144-linux-x64.rpm"
--2014-11-27 14:34:03--  http://download.oracle.com/otn-pub/java/jdk/8u25-b17/jdk-8u25-linux-x64.rpm
download.oracle.com (download.oracle.com) をDNSに問いあわせています... 203.179.83.21, 203.179.83.10
download.oracle.com (download.oracle.com)|203.179.83.21|:80 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 302 Moved Temporarily
場所: https://edelivery.oracle.com/otn-pub/java/jdk/8u25-b17/jdk-8u25-linux-x64.rpm [続く]
--2014-11-27 14:34:03--  https://edelivery.oracle.com/otn-pub/java/jdk/8u25-b17/jdk-8u25-linux-x64.rpm
edelivery.oracle.com (edelivery.oracle.com) をDNSに問いあわせています... 23.10.6.140
edelivery.oracle.com (edelivery.oracle.com)|23.10.6.140|:443 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 302 Moved Temporarily
場所: http://download.oracle.com/otn-pub/java/jdk/8u25-b17/jdk-8u25-linux-x64.rpm?AuthParam=1417066563_ad49f0ca150603a9804a860ade76ca62 [続く]
--2014-11-27 14:34:03--  http://download.oracle.com/otn-pub/java/jdk/8u25-b17/jdk-8u25-linux-x64.rpm?AuthParam=1417066563_ad49f0ca150603a9804a860ade76ca62
download.oracle.com (download.oracle.com)|203.179.83.21|:80 に接続しています... 接続しました。
HTTP による接続要求を送信しました、応答を待っています... 200 OK
長さ: 142191827 (136M) [application/x-redhat-package-manager]
`jdk-8u25-linux-x64.rpm' に保存中

100%[====================================================================================================================>] 142,191,827 2.69MB/s 時間 52s

2014-11-27 14:34:55 (2.61 MB/s) - `jdk-8u25-linux-x64.rpm' へ保存完了 [142191827/142191827]

ファイルサイズもちゃんとした、rpmがダウンロード出来ました。

Marvericksでbashを新しくしてみた。

とりあえずテスト

$ env x='() { :;}; echo !!!!!!!!!!' bash -c 'echo hello'
!!!!!!!!!!
hello

無事に脆弱性が確認出来ました。
ということで、新しいBashに入れ替えます。
幸いな事にmacportsには既に対策済みのがあるようなので、macportsでちゃちゃっと入れます。

$ sudo port selfupdate
$ sudo port upgrade 

としたところで、port使うのが久しぶりなせいか、xcodeがどうとか言ってきました。
おそらく普段からxcode使ってる人はこんな事言われずに普通に終わるんじゃないかなぁと思います。

Warning: The Xcode Command Line Tools don't appear to be installed; most ports will likely fail to build.
Warning: Install them by running `xcode-select --install'.
Error: It seems you have not accepted the Xcode license; most ports will fail to build.
Error: Agree to the license by opening Xcode or running `sudo xcodebuild -license'.
Error: Unable to upgrade port: 1
To report a bug, follow the instructions in the guide:
    http://guide.macports.org/#project.tickets

とりあえず言われるがままに

$ xcode-select --install

したら、こんな感じのウィンドウが出てきたので、
f:id:tottokug:20140925190632p:plain
インストールを押して数分後、インストール完了です。
f:id:tottokug:20140925190638p:plain


それで、今度はライセンスがどうのと言っているので確認して、agreeします。

$ sudo xcodebuild -license

気をつけなくてはいけないのは、長い文章が出てきて、最後に"agree"と打たないといけません。
適当にaと打ってreturnを押してしまうと、もう一回同じコマンドを打って、長い文章を見ないといけません。
ちゃんとagreeとうちましょう。xcodeも準備が出来たみたいなので、

$ sudo port upgrade bash

これでbashもいい感じになったはずです。

$ env x='() { :;}; echo !!!!!!!!!!' bash -c 'echo hello'
bash: 警告: x: ignoring function definition attempt
bash: `x' の関数定義をインポート中にエラーが発生しました
hello

ちゃんとエラーが出てくれるようになりました。