ぱせらんメモ このページをアンテナに追加 RSSフィード

とあるWeb系ソフトウェアエンジニアのブログ。
いちおう技術系ネタ帳ということで、日記はあまり書かない。

2012-01-22

xargsメモ

| xargsメモを含むブックマーク xargsメモのブックマークコメント

xargsはよくfindと組み合わせて一括処理したりするのに使うけど、失敗すると大ダメージを受けるのでお勉強。


プログラムを指定しないとecho

xargsにプログラムを指定しないとechoが使われるのでどんな感じに渡されるのか確認できる。

$ ls -l
total 0
-rw-r--r--  1 pasela  staff     0B  1 22 17:11 foo
-rw-r--r--  1 pasela  staff     0B  1 22 17:11 bar
-rw-r--r--  1 pasela  staff     0B  1 22 17:11 baz

$ ls | xargs
foo bar baz

NUL(\0)区切りで受ける

xargsはデフォルトではホワイトスペースで区切るので、たとえば"Foo Bar"というような空白を含むファイルがあるときに普通に実行すると残念なことになる。

$ ls -l
total 0
-rw-r--r--  1 pasela  staff     0B  1 22 17:11 Foo Bar
-rw-r--r--  1 pasela  staff     0B  1 22 17:11 baz

$ find . type -f -print | xargs rm
rm: ./Foo: No such file or directory
rm: Bar: No such file or directory

これはこんな感じの3引数として渡される。

rm "./Foo" "Bar" "baz"

これを避けるにはリストを\0区切りで出力して、受ける方も\0区切りで受けるとよい。

findのほうは-print0を使うと\0区切りで出力してくれ、xargsは-0で入力を\0区切りとして受け取れる。

$ find . type -f -print0 | xargs -0 rm

これはこんな感じの2引数として渡される。

rm "./Foo Bar" "baz"

ちなみにGNU版の場合は-d delimで他にも任意のデリミタを指定することができる。


実行コマンドを表示する

-tを指定すると実行するコマンドを表示してくれる。

$ ls | xargs -t
/bin/echo bar baz foo
bar baz foo

表示した上で実行もするので、dry run的な確認には使えない。勘違いしないように。

ログとして残したい場合なんかにいいかも?


実行するかどうか確認する

-pを指定するとコマンド実行毎に実行するかどうか確認してくる。yで実行、それ以外でスキップ。

$ ls | xargs -p
/bin/echo bar baz foo?...y
bar baz foo

入力n行ごとに実行する

-L 数字で指定行数ごとにコマンドを実行させられる。

$ ls | xargs -L 1 -t
/bin/echo bar
bar
/bin/echo baz
baz
/bin/echo foo
foo

$ ls | xargs -L 2 -t
/bin/echo bar baz
bar baz
/bin/echo foo
foo

引数n個ごとに実行する

-n 数字で指定個数の引数ごとにコマンドを実行させられる。

$ ls | xargs -n 1 -t
/bin/echo bar
bar
/bin/echo baz
baz
/bin/echo foo
foo

$ ls | xargs -n 2 -t
/bin/echo bar baz
bar baz
/bin/echo foo
foo

ん、-Lとの違いがわからない?

ではこうやって1行の入力にしてみると違いがわかるはず。

$ echo "foo bar baz" | xargs -n 1 -t
/bin/echo foo
foo
/bin/echo bar
bar
/bin/echo baz
baz

$ echo "foo bar baz" | xargs -L 1 -t
/bin/echo foo bar baz
foo bar baz

-nのほうはホワイトスペースで3つに区切られた上で、1つずつ実行されている。

-Lのほうは1行の入力ずつ実行されている。


置換文字列で挿入する

普通はxargsに渡したコマンドの最後にxargsが引数を追加して実行されるが、cpmvみたいにコマンドラインの途中の位置に挿入して欲しい場合は-I repstrが使える。

普通にやると……

$ ls | xargs -t cp /path/to/dest_dir
cp /path/to/dest_dir bar baz foo
usage: cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file target_file
       cp [-R [-H | -L | -P]] [-fi | -n] [-apvX] source_file ... target_directory

こんな感じのコマンドラインで実行されてしまうが、-Iを使うと……

$ ls | xargs -I % -t cp % /path/to/dest_dir
cp bar /path/to/dest_dir
cp baz /path/to/dest_dir
cp foo /path/to/dest_dir

このように-Iで指定した文字列のところを置換して処理してくれる。


BSDの場合)もうちょっと賢く

上記のは見てのように自動的に-L 1として処理されてしまうので効率があまりよくない。

ここはcp bar baz foo /path/to/dest_dirってなってほしいよね?

こういう場合、BSD版なら-J repstrを使うとよい。

$ ls | xargs -J % -t cp % /path/to/dest_dir
cp bar baz foo /path/to/dest_dir

複数プロセスで並列に実行する

-P 数字を使うと指定したプロセス数で並列実行してくれる。デフォルトは1。

例えばこんな感じのURLリストがあったとして……

$ cat urls.txt
http://www.google.co.jp/
http://www.yahoo.co.jp/
http://www.goo.ne.jp/

こんな感じで実行すると普通は1つずつ実行される。

$ cat urls.txt | xargs -n 1 -t curl >/dev/null
curl http://www.google.co.jp/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 12352    0 12352    0     0   130k      0 --:--:-- --:--:-- --:--:--  177k
curl http://www.yahoo.co.jp/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 25694    0 25694    0     0  53247      0 --:--:-- --:--:-- --:--:--  253k
curl http://www.goo.ne.jp/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 64743    0 64743    0     0   630k      0 --:--:-- --:--:-- --:--:--  916k

-Pを指定してやるとこれを並列に実行して一気にダウンロードできる。

$ cat urls.txt | xargs -n 1 -P 3 -t curl >/dev/null
curl http://www.google.co.jp/
curl http://www.yahoo.co.jp/
curl http://www.goo.ne.jp/
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 12340    0 12340    0     0   127k      0 --:--:-- --:--:-- --:--:--  191k
100 64796    0 64796    0     0   590k      0 --:--:-- --:--:-- --:--:--  832k
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 25703    0 25703    0     0  59137      0 --:--:-- --:--:-- --:--:--  522k
トラックバック - http://d.hatena.ne.jp/pasela/20120122

2012-01-06

Webカラー名を一覧表示するunite source作ってみた

| Webカラー名を一覧表示するunite source作ってみたを含むブックマーク Webカラー名を一覧表示するunite source作ってみたのブックマークコメント

vimにもカラーピッカーみたいなプラグインはいくつかあって、自分はcolorsel.vimとかColorV.vimを使っていたんだけど、ColorVのカラーリストがなんとなく気に入らなかったので、uniteのソースとして自作してみることにした。


unite-webcolorname

https://github.com/pasela/unite-webcolorname


こんな感じで色を選択して挿入したりコピーしたりできる。

f:id:pasela:20120106211509p:image


Vim script自体もあんまり書いたことないしuniteのsourceも作ったことなかったので、あちこちのsource plugin見ながらなんとか作ってみたよ。

シンタックスハイライトの例がほとんどなかったのと、ハイライトの目的がちょっと普通じゃないので試行錯誤が必要だったけど、こんな感じに綺麗にできた。


選択中の項目が白くなっちゃうのがちょっと残念だけど、まぁ仕方ないかな?

カーソル下のcandidateから色取ってCursorLineを逐一書き換えるという方法も浮かんだけどそもそもできるのかわからないし、選択中の項目がわかりにくくなりそうだからまぁいいかな、と。気が向いたらそのうちやってみるかも。

トラックバック - http://d.hatena.ne.jp/pasela/20120106

2011-12-26

Node.jsはじめてみた

| Node.jsはじめてみたを含むブックマーク Node.jsはじめてみたのブックマークコメント

話題……というには今更だけどなんとなくNode.jsを始めてみた。

本当はSymfony2をモノにしようと勉強する予定だったんだけど、飲み会で「Node.jsやりたい!」って言ってる人がいて「ふーん」と思いつつもちょっと気になって手を出してみた。そしたらなんか面白くなってきてハマっちゃったかもw


Node.jsに抱いていたイメージ

自分がNode.jsに抱いていたイメージは「サーバサイドJavaScriptの一種」「ノンブロッキングI/Oとイベントループで大量のアクセスもさばけるらしい」とかそんな程度だった。最近だと「WebSocketのために使われる」みたいなイメージも。

でもまぁ、一部の用途ではいいソリューションになるんだろうなーと思いつつも、どこか「面白そうだったのでサーバサイドでJavaScript使えるようにしてみましたー」的な遊びっぽいイメージのほうが強かった。

けど、どうもそうじゃなかったらしい。


Node.jsとは何か

Node.jsを試してみるにあたって、とりあえず情報収集していると“node.jsとは何か”という自分の疑問にずばり答えてくれそうなエントリが見つかった。(4)まであるので自分みたいに「Node.jsって結局なんなの?」って思ってる人は是非とも読むべし。


簡単にまとめるとこういうことらしい。

  • C10k問題でよく比べられているアーキテクチャスレッドモデルとイベントループモデルがある。*1
  • スレッドは数が多くなるとメモリ消費量が増える。
  • 対してイベントループは1プロセスのままなのでたいしてメモリ消費量は増えない。
  • だけどイベントループはどこかにブロックするやつがいると全体の処理が止まってしまって大変!
  • そして既存の言語にもイベントループの実装はあるけど、Non-Blocking I/Oを強制しているわけではないので止まってしまう不安がつきまとう。
  • 対してJavaScriptは元々がシングルスレッドでイベントループという仕組みを持っていた。
  • さらにWebやってる人ならだいたいJavaScriptは触ったことあるよね!→学習コストが低い。
  • さらにGoogle V8という高性能で組み込みやすいJavaScriptエンジンがある!

こうしてNode.jsは誕生したらしい。


とりあえず環境を作ってみる

前置きがすごーーーーーく長くなったけど対象のことを知るのは大事よってことで。むしろ、どういうものかわかったことで俄然興味が湧いてきた。


さてさて、自分はMacなのでhomebrewで簡単にインストールできるみたいなんだけど、どうやらnaveとかnvmっていう環境管理ツールを使うのがいいらしい。

RubyのRVMやPerlPerlbrewPythonのvirtualenvみたいなやつで、Node.jsをバージョンごとにインストールして切り替えたりできるやつ。

nave

https://github.com/isaacs/nave

  • npmというNode.jsにおけるパッケージ管理システムの作者が作成しているので、なんとなく安心感がある。
  • nave useするときにシェルが再実行されるのでなんとなく気持ち悪い。環境変数とかぐちゃっとしそうだし。そのうち改善されるかな?
nvm

https://github.com/creationix/nvm

  • npmもインストールしてくれる。らしいけど、最近は最初からNode.jsについてる?
  • nvm useしてもPATHとかをexportし直すだけでシェルを多重起動したりしない。
  • zshといまいち相性が良くない。時々エラーが出たりする。が、概ね動く。

nvmのインストール

自分はnvmを入れてみたけど、たぶんどっちも大差ないと思う。

というわけでnvmのインストール

git clone git://github.com/creationix/nvm.git ~/.nvm
source ~/.nvm/nvm.sh

んで、.bashrcとか.zshrcにもsource ~/.nvm/nvm.shを書いておく。

これで完了。

ちなみにnaveの場合はsourceで読み込む必要もなく、nave.shを落としてきてそれをコマンドとして使えばいいみたい。


使い方はこれ系のツールとだいたい同じで、サブコマンドのinstallとかuseとかを使えばよい。とりあえず実行するとヘルプが表示される。


Node.jsインストール

さっそくnvmでNode.js本体をインストールしてみる。

nvm install v0.6.6

これだけ。で、使ってみる。

nvm use 0.6.6

これでv0.6.6が有効になった。


とりあえずHello, World!

Node.jsのトップにあるEXAMPLEを試してみよう。

var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(1337, "127.0.0.1");
console.log('Server running at http://127.0.0.1:1337/');

これをhello.jsとかに保存して

node hello.js

で実行。

ブラウザでhttp://127.0.0.1:1337/にアクセスすると「Hello World」が表示される。

シンプルなコードなのでだいたい上のコードがどういう内容なのか想像が付くはず。ちょっと肉付けしたら色々できそうでワクワクしてきたでしょ?


ライブラリとかフレームワークとか

Node.jsにはnpmという他の言語にもよくあるようなパッケージ管理システムがあって、これを使って色々なライブラリインストールできる。

MySQLクライアントのnode-mysqlとか、WebアプリケーションフレームワークのExpressとか、テンプレートエンジンのejsとかとにかく色々ある。


npm install express

ってな感じで簡単にインストールできる。


コマンドラインツールとして

ここまで来るまで実はNode.jsってWebサーバなんだと思ってたんだけど、サーバたらしめてるのはどう見てもrequireしてるhttpってやつやnetのおかげらしくて、普通にJavaScriptを書けばサーバでもなんでもない普通の処理もできるってことに気づいた。

実際そういう使い方もあるみたいだし、標準でReadlineライブラリもあるし、npmにはoptimistとかjs-optsといったgetopt系のライブラリもあるみたい。

組み込みライブラリ、npm含めて結構色々揃ってるからそういう使い方もいいかなーとか思ったり。

っていうか本体にREPLついてるじゃん!


ドキュメント

とりあえずこの辺のドキュメントが参考になった。


特にハンズオン資料は一通り目を通すとNode.jsで何ができるのか、どうしたらいいのかがざっくりと理解できる。

で、APIマニュアルにざっと目を通してどんな機能があるのか把握しておけばよいかと。目次見るだけでも色々あってワクワクするね!


今後やりたいこと

  • Expressでとりあえず普通にWebアプリ作ってみる
  • WebSocketでなんかリアルタイムに動くやつとか!
  • コマンドラインツールとして使ってみる

*1:よく例に挙げられる代表はApacheとnginx

トラックバック - http://d.hatena.ne.jp/pasela/20111226

2011-12-19

HTMLAnchorElement.hrefとElement.getAttribute("href")の違い

| HTMLAnchorElement.hrefとElement.getAttribute("href")の違いを含むブックマーク HTMLAnchorElement.hrefとElement.getAttribute("href")の違いのブックマークコメント

JavaScriptなんかでURIの示すリソースをどうこうするときに、どうしても絶対URIが欲しいことがあるんだけど、頑張って自分で組み立てなくても、相手がA要素なら意外と簡単に取れるみたい。


<a id="bar" href="../foo/bar.html">bar</a>

こんな感じのA要素があったとして、普通にHTMLAnchorElementオブジェクトのhrefプロパティを参照すると解決済みの絶対URIが入っているらしい。

ここでElement.getAttribute()を使うと現在設定されている値そのものが取れてしまう。

var link = document.getElementById('bar');

console.log(link.href);
// => http://example.com/path/to/foo/bar.html

console.log(link.getAttribute('href'));
// => ../foo/bar.html

仕様がいまいちわからない

ぐぐってみるとわりと常識らしいんだけど、どこまで信頼していいのか、ブラウザ互換性とかどうなのかがいまいちわからなかった。

DOM Level 2で規定されているという記述があったのでDOM Level 2 HTMLのHTMLAnchorElementのところを見てみると、

href of type DOMString
The absolute URI [IETF RFC 2396] of the linked resource. See the href attribute definition in HTML 4.01.

と書かれているので、この属性が絶対URIを扱うのは確かなようだ。


ただ、あまりにもそっけなく書いてあるので、相対URIを入れた場合はどうなるのか、自動的に絶対URIに変換してくれるのか、それとも設定する側が絶対URIを設定しなければいけないのか、とかいまいちよくわからない。

ちょっと試した感じだと相対URIを突っ込んでも読みだすときには絶対URIとして読み出せる模様。


「相対URIを絶対URIに変換するテクニック」のひとつとして、HTMLAnchorElementを生成してhrefプロパティから取り出すというのを時々見かけるので、きっと大概の環境で動くんだろう。うん、きっとそう。

トラックバック - http://d.hatena.ne.jp/pasela/20111219

2011-07-04

Macにpythonbrew+virtualenvでPython環境を作ってみた

| Macにpythonbrew+virtualenvでPython環境を作ってみたを含むブックマーク Macにpythonbrew+virtualenvでPython環境を作ってみたのブックマークコメント

RubyPerlときたので残るPythonについてもpythonbrewとvirtualenvで環境を整えてみた。いい加減内容がテンプレ的で飽きてきたけどw

PythonSnow Leopardでは2.6.1なので2.7とか3.2が使いたいよねーってことで。

タイトルには「Macで〜」って入ってるけど、pythonbrew自体はUNIX系の環境で使えます。


pythonbrewっていうのは、複数のPythonバージョンを簡単にインストールしたり切り替えたりできるようにするツールで、RubyでいえばRVM、Perlでいえばperlbrewみたいなもん。*1

これを使えばOS標準の環境も汚さないし、2.6系、2.7系、3系とかプロジェクトで使用中のバージョンと最新版とか色々な複数の環境を簡単に共存させて使い分けることができる。ステキ!


pythonbrewを使うとこんな感じでサクサク環境を使い分けることができるようになる。

pythonbrew install 2.7.2  ←Python-2.7.2をインストール
pythonbrew install 3.2    ←Python-3.2をインストール

pythonbrew switch 2.7.2   ←Python-2.7.2に切り替え
pythonbrew switch 3.2     ←Python-3.2に切り替え

virtualenvっていうのは、Pythonの新しい独立した環境を構築して自由に切り替えて使えるようにするツール。

pythonbrewと何が違うのかというと、pythonbrewはPythonインストールから管理してくれるのに対して、virtualenvは既存の実行環境を元にして新しい仮想環境を作ってくれる点が異なる。


virtualenvと、あとそれを便利にするvirtualenvwrapperっていうのを使うとこんな感じでサクサク環境を使い分けることができるようになる。

mkvirtualenv -p /path/to/python-2.6 foo       ←2.6をベースにfooという環境を作成
mkvirtualenv -p /path/to/python-2.6 foo2      ←2.6をベースにfoo2という環境を作成
mkvirtualenv -p /path/to/python-3.2 bar       ←3.2をベースにbarという環境を作成

workon foo     ←foo環境に切り替え
workon bar     ←bar環境に切り替え
deactivate     ←virtualenvの環境から抜けてOS標準に戻る

どっちかでいいんじゃないかって気もするけど、そう思うんならそれでいいんだと思う。

とりあえずpythonbrewで新しいインタプリタインストールして、virtualenvで用途別にぽこぽこ環境を増やしていくというのが流行りらしい(?)のでそれに倣ってみる。


pythonbrewのインストール

pythonbrewのインストール方法は公式サイトに書いてあるコマンドを叩けば簡単に入る。


utahta/pythonbrew - GitHub


curl -kLO https://github.com/utahta/pythonbrew/raw/master/pythonbrew-install
chmod +x pythonbrew-install
./pythonbrew-install

流れとしてはこんな感じ。

  1. インストールスクリプトを落としてシェルで実行
  2. $HOME/.pythonbrew/etc/bashrcを.bash_profileとか.bashrcで読み込むようにする

perlbrewと同じだね。

これで$HOME/.pythonbrewにpythonbrewの環境ができあがる。


pythonbrewに関するコマンド

pythonbrewで入れることのできるバージョン一覧

pythonbrew list -k

pythonbrewのアップデート

pythonbrew update

これでpythonbrewが最新になる。


Pythonインストール

Pythonインストール

pythonbrew install 2.7.2

これでPython-2.7.2がインストールされる。


別名をつけてインストール

pythonbrew install --as=mypython 2.7.2

これでPython-2.7.2がmypythonという名前でインストールされる。


configureオプションを指定する

pythonbrew install --configure="CC=gcc_4.1" 2.7.2

アンインストール

pythonbrew uninstall 2.7.2

Pythonbrewを切り替える

入ってるPython一覧

pythonbrew list

これでインストールされているPythonの一覧が表示される。


Pythonを切り替える

pythonbrew switch 2.7.2

これで2.7.2を使うためのPATHとかその他の環境変数が切り替わったので、今すぐPython-2.7.2が使える状態になる。

RVMとは逆、perlbrewと同じで永続的に切り替わった状態になる。


現在のシェルだけ切り替える

pythonbrew use 2.7.2

切り替え状態はこのシェルだけ。


OS標準のPythonに戻す

pythonbrew off

これでperlbrewで入れたやつじゃない環境に戻る。


複数のPythonでまとめて実行

pythonbrewにはインストールしてあるPythonでまとめて実行する機能がある。

これを利用すると書いたプログラムが他のバージョンでもちゃんと動くか一発でテストできる。


まとめて実行

pythonbrew py hello.py

pythonbrewでインストールした全Pythonで実行される。


特定のバージョンで実行

pythonbrew py -p 2.6.6 -p 2.7.2 hello.py

2.6.6と2.7.2で実行される。


リンクを張る

pythonbrew symlink

こうするとpy2.6とかpy2.7.2みたいなリンクが.pythonbrew/binに出来るので手軽に実行出来るようになる。

ただしpythonbrew offするとリンクも消えてしまうみたい。


あと、実はpythonbrewはpybrewというコマンド名でも実行できる。


virtualenvとvirtualenvwrapper

続けてvirtualenvのインストール

とりあえずどれでもいいのでvirtualenvを入れたい環境にswitchする。

pythonbrew switch 2.7.2

pipでvirtualenvとvirtualenvwrapperをインストール

pythonbrewによってeasy_installとpipもインストールされている。

pip virtualenv virtualenvwrapper

.bashrcとかに環境変数VIRTUALENVWRAPPER_PYTHONを設定する。

VIRTUALENVWRAPPER_PYTHON=$HOME/.pythonbrew/pythons/Python-2.7.2/bin/python

pythonbrew symlinkでできたpy2.7.2とかを指定するのがいいっぽいんだけど、pythonbrew offすると消えちゃうので直に指定してみた。


.bashrcとかでvirtualenvwrapper.shを読み込む。

source $HOME/.pythonbrew/pythons/Python-2.7.2/bin/virtualenvwrapper.sh

これもpythonbrew symlink -d 2.7.2 virtualenvwrapper.shとかでできたのを指定するっぽいんだけど(ry


virtualenvで環境を操作する

まー、冒頭のサンプルの通り。

それ以外に一覧を表示するlsvirtualenvとか、環境を削除するrmvirtualenvとか色々ある。

詳しくは公式ドキュメントのコマンドリファレンスを参照。


参考

*1perlbrewインスパイアされてできたらしい。