Windows/Linux/OS X、どんな環境でも動くBash Likeなスクリプトをを書ける「shelljs」はどうだろうか？

時として、マルチプラットフォームで動作するスクリプトを書きたいときがあります。しかし、システムが違うために、どうしてもスクリプトの共通化のできない箇所が存在します。「shelljs」はそんな悩みを少しだけ解決してくれるかもしれないライブラリです。

- http://documentup.com/shelljs/shelljs
- https://github.com/shelljs/shelljs

shelljs(概要)
-----

> ShellJS is a portable (Windows/Linux/OS X) implementation of Unix shell commands on top of the Node.js API. You can use it to eliminate your shell script's dependency on Unix while still keeping its familiar and powerful commands. You can also install it globally so you can run it from outside Node projects - say goodbye to those gnarly Bash scripts!

*ShellJSは、移植可能な（Windows / Linux / OS X）のUnixシェルコマンドをNode.js APIの上に実装したものです。シェルスクリプトを使用して、シェルスクリプトのUnix依存性を解消しながら、使い慣れた強力なコマンドを使用することができます。また、それをグローバルにインストールすることもできますので、Nodeプロジェクトの外部から実行することができます。ちょっとしたバッシュスクリプトにさよならを言いましょう！*

紹介
-----

説明にもありますが、ShellJSはUnix上いろいろな便利なコマンドをNodeJS上に再実装して、ライブラリ化したものです。ここまで聞くと、内部で`exec`しているのでは？と勘ぐってしまいますが、そんなことはありません。**完全なJS実装**です。(自分も、ソースコードを読むまでそう思っていました)

導入
-----

導入はとてもかんたん

```bash
$ npm install [-g] shelljs
```

あとは、スクリプトから呼び出すだけ

```js
var shell = require('shelljs');

if (!shell.which('git')) {
  shell.echo('Sorry, this script requires git');
  shell.exit(1);
}

// Copy files to release dir
shell.rm('-rf', 'out/Release');
shell.cp('-R', 'stuff/', 'out/Release');

// Replace macros in each .js file
shell.cd('lib');
shell.ls('*.js').forEach(function (file) {
  shell.sed('-i', 'BUILD_VERSION', 'v0.1.2', file);
  shell.sed('-i', /^.*REMOVE_THIS_LINE.*$/, '', file);
  shell.sed('-i', /.*REPLACE_LINE_WITH_MACRO.*\n/, shell.cat('macro.js'), file);
});
shell.cd('..');

// Run external tool synchronously
if (shell.exec('git commit -am "Auto-commit"').code !== 0) {
  shell.echo('Error: Git commit failed');
  shell.exit(1);
}
```


見ての通り、かんたんに書くことができます。


使った感想
----

このライブラリは、

- 簡単に、慣れたAPIで素早く実装できる
- 実行効率は考慮しない
- 非環境依存で実装できる

という部分に重きをおいているように感じます。
その為、git-hookなどのライブラリごとのスクリプトや、gulpなどのタスクランナーなどの処理に向いていると思いました。
メモリ上ではなく、ファイルに書き起こしたり、ファイルから読んだりと、ファイル中心の処理を行っているので、これをWebアプリケーションなどの常駐型のアプリに組み込むのはBadかもしれませんが、バッチ処理ならばとてもいい感じで組めそうです。



shelljsのAPI一覧
----

- cat([options,] file [, file ...])
- cat([options,] file_array)
- cd([dir])
- chmod([options,] octal_mode || octal_string, file)
- chmod([options,] symbolic_mode, file)
- cp([options,] source [, source ...], dest)
- cp([options,] source_array, dest)
- pushd([options,] [dir | '-N' | '+N'])
- popd([options,] ['-N' | '+N'])
- dirs([options | '+N' | '-N'])
- echo([options,] string [, string ...])
- exec(command [, options] [, callback])
- find(path [, path ...])
- find(path_array)
- grep([options,] regex_filter, file [, file ...])
- grep([options,] regex_filter, file_array)
- head([{'-n': },] file [, file ...])
- head([{'-n': },] file_array)
- ln([options,] source, dest)
- ls([options,] [path, ...])
- ls([options,] path_array)
- mkdir([options,] dir [, dir ...])
- mkdir([options,] dir_array)
- mv([options ,] source [, source ...], dest')
- mv([options ,] source_array, dest')
- pwd()
- rm([options,] file [, file ...])
- rm([options,] file_array)
- sed([options,] search_regex, replacement, file [, file ...])
- sed([options,] search_regex, replacement, file_array)
- set(options)
- sort([options,] file [, file ...])
- sort([options,] file_array)
- tail([{'-n': },] file [, file ...])
- tail([{'-n': },] file_array)
- tempdir()
- test(expression)
- ShellString.prototype.to(file)
- ShellString.prototype.toEnd(file)
- touch([options,] file [, file ...])
- touch([options,] file_array)
- uniq([options,] [input, [output]])
- which(command)
- exit(code)
- error()
- ShellString(str)
- env['VAR_NAME']
- Pipes

参考
-----

- http://documentup.com/shelljs/shelljs
- https://github.com/shelljs/shelljs