【PowerShell】他プロセスの実行方法まとめ

2018/11/22 追記

以下の修正を行いました。

  • ちゃんとシンタックスハイライトを適用しました。
  • 呼び出し元のプロセスに標準 / エラー出力をリダイレクトする方法を追記しました。
  • 一部のリンクが 404 を返すようになったので削除しました。

前書き

何だかんだで最近 PowerShell を書く機会が増えまくっています。まぁ中身はほとんど C#なんですが。

で、全部 C#で書いてもいいんだけど、外部ツール使えば一瞬みたいなものもあるので、そう言うものはなるべくそっちでやってしまいたいです。特に zip 関連の処理。

シェルってぐらいなんだからそれぐらい簡単にできるでしょー?と思っていたら大分ハマったので色々とメモしておきます。

実行例

引数で受け取ったフォルダのサブフォルダ内にある zip ファイルをC:\Program Files\7-Zip\7z.exeで解凍する、みたいなパターン。7z.exe にパスは通していない状態。

コマンドはxコマンドを使います。

大体こんなコードになります。Get-ChildItem?何のことかよくわからないですね…。

$nIO = "System.IO"
$cDirectory = "$nIO.Directory" -as [type]

foreach($root in $cDirectory::GetDirectories($args[0])) {
    foreach($7zFile in $cDirectory::GetFiles($root,"*7z")) {
        #ここで7zipを使って解凍したい
    }
}

普通に実行する

何をもって普通と呼ぶのかですが、こんな風にすりゃ呼べるんじゃねーの?と普通は思います。

$nIO = "System.IO"
$cDirectory = "$nIO.Directory" -as [type]

$7zexe = "C:\Program Files\7-Zip\7z.exe"

foreach($root in $cDirectory::GetDirectories($args[0])) {
    foreach($7zFile in $cDirectory::GetFiles($root, "*7z")) {
        # ここで7zipを使って解凍したい
        $7zexe x -o$root $7zFile
    }
}

$root$7zFileにスペースが入っていたりするとやっぱりダメなので、安全性を鑑みてこのようにするのがベストでしょう。

$nIO = "System.IO"
$cDirectory = "$nIO.Directory" -as [type]

$7zexe = "C:\Program Files\7-Zip\7z.exe"

foreach($root in $cDirectory::GetDirectories($args[0])) {
    foreach($7zFile in $cDirectory::GetFiles($root,"*7z")) {
        #ここで7zipを使って解凍したい
        & $7zexe x -o"$root" "$7zFile"
    }
}

ちなみにこの&Invoke-Expressionエイリアスです。まぁわざわざInvoke-Expressionなんて長ったらしいコマンドを書く必要は皆無なので tips として覚えておきましょう。

また、似たようなコマンドレットにInvoke-Itemがありますが、使える範囲が非常に狭いので覚えなくていいです。(既定のプログラムで txt 開きたいとかのケースだと使えるけど…。)

また、$?を使うことで直前のコマンドが成功したかどうかを boolean で取得できるので、こんなこともできます。

$nIO = "System.IO"
$cDirectory = "$nIO.Directory" -as [type]

$7zexe = "C:\Program Files\7-Zip\7z.exe"

foreach($root in $cDirectory::GetDirectories($args[0])) {
    foreach($7zFile in $cDirectory::GetFiles($root,"*7z")) {
        #ここで7zipを使って解凍したい
        & $7zexe x -o"$root" "$7zFile"

        if($?) {
            #解凍後にzipを削除する
            [System.IO.File]::Delete($7zFile)
        }
    }
}

Start-Processを使う

他の方法としてはStart-Processコマンドレットを使用する必要があります。 System.Diagnostics.Process::Startみたいなもんだと思えば OK です。

Start-Processのパラメータ

色々と引数がありますが、頻繁に使うのはこのあたりでしょうか。

パラメータ 用途
-FilePath 実行ファイルのパス。パス内にスペースが入っているとキレられるので、ダブルクオーテーションでくくってやる必要がある。
-ArgumentList 実行ファイルへ渡す引数。一応String[]を受け付けるが、普通に一個のStringを渡す方が安全。
-NoNewWindow プロセス実行時に別ウィンドウを立ち上げない。-WindowStyleとは併用不可。
-PassThru 実行するプロセスのオブジェクトを生成してくれる。デフォルトではオフなので、戻り値が欲しい時は必須のパラメータとなる。後述。
-Wait 指定したプロセスの実行が完了するまで PowerShell が待っていてくれる。
-WindowStyle プロセスを実行する際のウィンドウサイズを指定。規定値はNormal-NoNewWindowとは併用不可。

-WindowStyleに指定可能な値

-WindowStyleには以下の値を設定することができます。内容は読んで字の如く。

  • Normal
  • Hidden
  • Minimized
  • Maximized

Start-Processでのプロセス実行例

と言うわけで、先ほどの処理を行うならこんな感じですね。

$nIO = "System.IO"
$cDirectory = "$nIO.Directory" -as [type]

$7zexe = "C:\Program Files\7-Zip\7z.exe"

foreach($root in$cDirectory::GetDirectories($args[0])) {
  foreach($7zFile in $cDirectory::GetFiles($root,"\*7z")) {
    #ここで 7zip を使って解凍したい
    $arg = "x -o`"$root`" `"$7zFile`""
    Start-Process -FilePath $7zexe -ArgumentList $arg -Wait -NoNewWindow
  }
}

ただこの方法、標準出力 / エラー出力を取得することが出来ません…。

-PassThru を使って更に細かい制御を行う

先述した通り、-PassThruオプションをつけるとプロセスのオブジェクトを作成してくれます。

具体的には、System.Diagnostics.Processが取得できます。

Processに含まれるプロパティExitCodeを見ることで処理結果からその後の処理を分岐させることが可能です。

$nIO = "System.IO" 
$cDirectory = "$nIO.Directory" -as [type]

$7zexe = "C:\Program Files\7-Zip\7z.exe"

foreach($root in $cDirectory::GetDirectories($args[0])) {
    foreach($7zFile in $cDirectory::GetFiles($root,"*7z")) {
        #ここで7zipを使って解凍したい
        $arg = "x -o`"$root`" `"$7zFile`""
        $proc = Start-Process -FilePath $7zexe -ArgumentList $arg -Wait -NoNewWindow -PassThru
        
        if($proc.ExitCode -eq 0) {
            #解凍後にzipを削除する
            [System.IO.File]::Delete($7zFile)
        }
    }
}

他にもWaitForExitメソッドあたりを使ってタイムアウトの制御なんかもできます。(当然-Waitオプションをはずさないと意味ないですが)

System.Diagnostics.Processを使う

え?PowerShell の文法なんか覚えられない?じゃあ C#書いたら?

$nIO = "System.IO"
$cDirectory = "$nIO.Directory" -as [type]
$nDiagnostics = "System.Diagnostics"

$7zexe = "C:\Program Files\7-Zip\7z.exe"

foreach($root in $cDirectory::GetDirectories($args[0])) {
    foreach($7zFile in $cDirectory::GetFiles($root,"*7z")) {
        #ここで7zipを使って解凍したい
        $arg = "x -o`"$root`" `"$7zFile`""
        $proc = New-Object "$nDiagnostics.Process"
        $psi = New-Object "$nDiagnostics.ProcessStartInfo"

        $psi.FileName = $7zexe
        $psi.Arguments = $arg
        $psi.UseShellExecute = $false
        $psi.WindowStyle = [System.Diagnostics.ProcessWindowStyle]::Hidden

        $proc.StartInfo = $psi

        $proc.Start()
        $proc.WaitForExit()

        if($proc.ExitCode -eq 0) {
            #解凍後にzipを削除する
            [System.IO.File]::Delete($7zFile)
        }
    }
}

とまぁ、見ていただくとわかるんですがすげー冗長です。シェルとは何だったのか。

ただ、Start-Processとは違ってSystem.Diagnostics.ProcessStartInfoをこちらで用意できるので、標準出力 / エラー出力をごにょごにょし放題です。

呼び出し元のプロセスと同じ標準出力 / エラー出力にリダイレクトさせるだけなら、以下のプロパティをtrueにすれば OK です。

また、この記事Process.OutputDataReceivedの設定方法などが詳細に解説されていますので、興味ある人はどうぞ。私はスクリプトのためにそこまでしないタイプの人間なので紹介だけにとどめておきます。

まとめ

PowerShell 使いにくい。

参考

【VSCode】Visual Studio Code 0.3.0の新機能まとめ

前書き

いつの間にかVSCodeが0.3.0にバージョンアップしていました。

「0.2.0は?」とか「起動時に毎回やってる自動アップデートチェックとは一体何だったのか」とか色々思うことはあるんですが、気が付かなかったことにしましょう。0.2.0は色々あったみたいですが、見なかったことにしましょう。

アップデート方法

再インストールしてください。

C:\Users\{UserName}\AppData\Local\Code\app-0.3.0にまるっと新しいものがインストールされます。日本語フォントを適用するためにcssを直接いじってたりすると強制的に元に戻されてしまいますが、app-0.1.0に元のソースやバイナリがそのまま残っているので、適当にマージしましょう。

新機能

Updatesに色々書かれているので、適当に翻訳していきます。

新しいキーバインド

色々な要望を受けてデフォルトのキーバインドを改善したようです。

  • Ctrl+Oでネイティブなファイル選択ダイアログが出るようになりました。各所から強い要望があったそうです。
    • VSCodeのファイル選択ダイアログ(コマンドパレットっぽいあれ)はCtrl+P⌘Pに変更したようです。「今の主要なエディタだとCtrl+Pで開くほうがトレンドだから!」と言い訳がましいことが書いてあります。
  • Visual Studioと同じくF12で定義にジャンプできるようになりました。(Ctrl+F12から変更)
  • Macでファイルの先頭/末尾への移動がCmd+UpCmd+Downで行えるようになりました。
  • コードのフォーマットを⇧⌥Fで行えるようになりました。(WindowsだとShift+Alt+FLinuxだとCtrl+Shift+Iで元々できました)

起動時の引数

存在しないファイルが引数で渡されたら新規ファイルを作成するようになりました。

(正確には「VSCodeで保存すると初めて作成されるDirtyなファイル」とのこと。)

code mynewfile.js

また、複数のファイルやディレクトリを引数で渡すことである程度最初からWorking Spaceを作れるようになりました。

code c:\myfolder1 c:\myfolder2 c:\myapp\program.cs

最後に、前回のセッション内容を復元しないで起動できるように-n--new-window)と言うオプションが追加されました。

code -n

コード編集

複数選択

  • Ctrl+D⌘D)を押すことでカーソル上の単語を選択、選択中に同コマンドを押すことで次に現れる同単語も選択できるようになりました。
  • Ctrl+K → Ctrl+D⌘K → ⌘D)で同単語を選択しつつカーソルを移動させることもできます。
  • 検索ボックス(Ctrl+F)が開いた状態で上記コマンドを入力すると即座に検索単語になります。
  • Ctrl+U⌘U)でカーソルの位置をアンドゥできるようになりました。
  • Ctrl+Alt+UpMac:⌥⌘↑, Linux:Ctrl+Meta+Up)とCtrl+Alt+DownMac:⌥⌘↓, Linux:Ctrl+Meta+Down)を使うことで複数選択しながらページを移動できます。

コメント

  • Ctrl+K → Ctrl+C⌘K → ⌘C)で選択行をコメントアウトできるようになりました。
  • Ctrl+K → Ctrl+U⌘K → ⌘U)で選択行のコメントを外せるようになりました。
  • 元々Ctrl+/⌘/)で行コメントの切り替えができたんですが、選択文字列内の空白行(ホワイトスペースのみ含む)では何も追加/削除しないようになりました。
  • 同じく、ブロックレベルのコメント切り替えであるShift+Alt+AMac:⇧⌥A, Linux:Ctrl+Shift+A)でも選択行の内容を見るようになりました。

インデント

空白行でTabを押したらちゃんと前行を見て必要な分だけインデントしてくれるようになりました。

選択範囲の拡張/縮小

Shift+Alt+Left^⇧←)とShift+Alt+Right^⇧→)を使って選択範囲の拡張/縮小が行えるようになりました。

どんなイメージかはgif動画があるんでそれを見てください。

禁則処理

settings.jsoneditor.wrappingIndentと言うプロパティが追加されました。指定できる値は以下の通りです。

  • none
  • same(これがデフォルト)
  • indent

長い文章が入力されるとそれぞれこんな感じになります。

    #none
    var str = "Lorem ipsum dolor sit amet, consectetur adipisicing elit
, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi
ut aliquip ex ea commodo consequat."

    #same
    var str = "Lorem ipsum dolor sit amet, consectetur adipisicing elit
    , sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
    Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris
    nisi ut aliquip ex ea commodo consequat."
    
    #indent
    var str = "Lorem ipsum dolor sit amet, consectetur adipisicing elit
        , sed do eiusmod tempor incididunt ut labore et dolore magna
        aliqua. Ut enim ad minim veniam, quis nostrud exercitation
        ullamco laboris nisi ut aliquip ex ea commodo consequat."

デバッグ機能

正直、VSCodeのデバッグ機能って使ったことないんですが…。

ドキュメントもちゃんとアップデートされているので、よくわからなかったらそっちも読んでください。

  • 接続時の設定(launch.json)としてruntimeArgsが追加されました。Node.jsやMonoにコマンドライン引数を渡す時に便利だそうです。
  • Linuxではデバッグ開始時に入出力をサポートするterminalを自動で開くようにしたそうです。
  • TypeScriptのデバッグ時にJavaScriptのsource mapと連携できるようになりました。接続時の設定でsourceMapstrueにすると使えるようです。
  • program属性にTypeScriptファイルを明示できるようになりました。
  • TypeScriptファイルからsource mapを生成してくれるようになりました。
  • 現在のセッションで開いていないフォルダ内のコードもデバッグできるようになりました。
  • 例外が発生したらその場所を赤く表示するようになりました。

この他にも多数の改善が行われています。UNCパス上のファイルをデバッグできるようになっていたりとか、MonoのF#(!)をデバッグできるようになっていたりだとか。

…って言うか、WindowsC#はいつサポートされるんですかね?

タスク

新たに三つのproblem matcherが追加されました。JSHintESLintの結果を受け取れるようになっています。

  • $jshint-stylish
  • $eslint-compact(※元文章では$eshint-compactとなっているが、Taskのドキュメントを読む限り誤記だと思われる。)
  • $eslint-stylish

また、ESLintのように複数行にまたがって取得する情報が展開されるものをどうにかするためにMulti Line Problem Matcherなるものも用意されました。

Taskの機能そのものより、ドキュメントの整備具合が大幅に向上したって感じです。がっつりtask.jsonを書くならSchema for tasks.jsonに一度は目を通しておきましょう。

言語対応状況

  • Rustの色分けとブラケットに対応。
  • TypeScript version 1.5に対応。
  • JavaScriptのvalidationのon/offを切り替えるプロパティが追加されました。主にJSHintを使う人向け。
    • javascript.validate.semanticValidation
      • 型はboolean。未使用変数が存在するとかのエラーを通知
    • javascript.validate.syntaxValidation
      • これもboolean。ブラケットが閉じてないとかのエラーを通知
  • HTMLで自動でタグを閉じてくれるようになりました。

CJK wrapping

今度は自然言語のお話。CJKとは「Chinese-Japanese-Korean」とのこと。左記の言語で禁則処理をきちんと行うようになりました。

また、変換を確定した時に変な挙動になるのも直ったみたいです。

…が、ファイル内に日本語が含まれているとOmniSharpがおかしくなるのは直ってない模様。Windowsだけなのかなー。って言うかこれはRoslynの問題な気もする。でもScriptCSは大丈夫だしなぁ…。

ファイル比較

コマンドパレットからファイル比較が簡単にできるようになりました。Files: Compare Opened File Withで可能です。

パスのコピー

Explorerペインで右クリックした時にパスをコピーできるようになりました。

現在開いているパスのコピーはコマンドパレットのFiles: Copy Path of the Active Fileで可能です。

Close Folder

メニューバーのFileか、コマンドパレットからClose Folderを選択することで現在開いているフォルダを閉じることができるようになりました。

ファイルエンコーディング

何だかんだで今回一番の目玉。UTF-8以外のエンコーディングに対応しました。

デフォルトではUTF-8のままですが、settings.jsonfiles.encodingを修正することで変更できます。

ちなみに文字コードの自動判別とかは一切ないです。ダメじゃん。

設定

VSCodeあるあるとして「setting.jsonの内容を自動補完で書いたせいで最後に,がついて怒られる」と言うのがあるんですが、これを無視してくれるようになりました。

まぁでも、怒りっぱなしなんですけど。

UNCパスのサポート

前から思ってたんだけど、VSCodeチーム、Windowsのこと嫌いだよね?

Working filesの監視

フォルダを開いていなくてもWorking files内のファイルは変更を監視するようになりました。

32bit版Linuxへの対応

対応したそうです。(雑)

まとめ

とまぁ、色々「どーなってんじゃい!」みたいなところが少しずつ修正されています。

次回は自動アップデートがちゃんと意味をなしてくれるといいですね!(皮肉)

【PowerShell】PowerShellでC#っぽいスクリプトを組むときの覚書

前書き

こう、「超単純だしC#なら10分ぐらいで書けるんだけど手作業でやると恐ろしく時間がかかる」みたいな作業ってあるじゃないですか。

そう言うのは最近ScriptCSで書いてるんですけど、あれの弱点って「どんな端末でも実行できるわけではない」なんですよね。.NET 4.5以上が必須だし、そもそもScriptCS自体がない。

Windows Server上での作業だとか、メインで使っているのとは別の開発端末での作業とか、「こいつ叩けば一発っすよ。」と鼻をほじりながら誰かに渡したりするようなスクリプトを書きたいときにはどうしても別の方法を考えなきゃいけません。

ってなると、じゃあbatでも書く?ってなるんですが、あれを書くエネルギーって本当にもったいないじゃないですか。デバッグは大変だし、文法はクソだし、文法はクソだし、文法はクソだし。

System.IO.PathとかSystem.IO.Directoryとかが使えればこんなの一発なのに…!ついでにSystem.DateTimeとかもあったら完璧なのに…!と思ったら、さっさとPowerShellで書くことにしました。

この文章の対象読者

PowerShellの文法を覚えるのは面倒だけどC#っぽいことができるスクリプトを書きたい人

下準備

PowerShellの環境を準備する

準備と言っても、Windows 7Windows Server 2008 R2からは標準搭載です。XPは標準搭載ではないですが、Windows Updateで取得できます。まぁ、XPなんて流石にもう使ってないと思うんですが…。使ってないですよね?

そんなわけで、今ならbatと同じぐらいの感覚で「これ使って」とばらまくことが可能です。実際に書いてる人を全然見たことがありませんが。

IDEの準備をする

PowerShellをインストールすると勝手にPowerShell ISEなる統合開発環境がくっついてきます。

…が、ver.1~2は「PowerShellシンタックスを綺麗に色分けしてくれるちょっと重いエディタ」でしかないです。(デバッグ機能はあるけども)

ver.3以降はインテリセンスが使えるので、可能であればアップデートしてきましょう。可能でなければ、頑張るだけです。

実際に書いてみる

オブジェクトを作る

New-Objectと言うコマンドレットがコンストラクタのかわりです。

ドキュメントには色んな引数が書いてありますが、基本的にはこんな感じでOKです。

$l = New-Object System.Collections.Generic.List[string]

New-Object 名前空間.型名って感じですね。ジェネリクス<T>ではなく[T]になります。

引数を渡すことも当然可能です。複数ある場合は,でOK。

$l = New-Object System.Collections.Generic.List[string](20)

プロパティをセットすることもできますが、インテリセンスが効かないのでオススメしません。

#意味不明なコードだ…。
$l = New-Object System.Collections.Generic.List[string](20) -Property @{Capacity=30}
$l.Capacity
# => 30

静的メソッドを呼び出す

[名前空間.型名]::メソッドで呼び出せます。

$tuple = [System.Tuple]::Create("hoge", 0)
$tuple.Item1
# => hoge
$tuple.Item2
# => 0

usingっぽいことをする

今までの例を見てもらえればわかるんですが、いちいち名前空間を書くのが結構面倒くさいです。(ISE ver.3以降であればインテリセンスである程度補完できますが…。)

PowerShellの文法にはC#のusingに該当するシンタックスはありませんが、近いことはできます。

# 名前空間を文字列で保持しておく
$nGeneric = "System.Collections.Generic"

# New-Objectの際に型名を文字列で渡す
$l = New-Object "$nGeneric.List[string]"
$l.Add("hoge")
$l.Add("fuga")
$l

# => hoge
# => fuga

静的メソッドを呼ぶ場合はもう一手間必要です。

$nIO = "System.IO"

# デフォルトで読み込まれていないアセンブリならロードしておく必要がある
#[Reflection.Assembly]::LoadWithPartialName($nIo)

# Typeにキャストする
$cPath = "$nIO.Path" -as [type]

$cPath::GetFileName("C:\test.txt")
# => test.txt

どちらもインテリセンスが効かなくなってしまうんですが、F8で選択した文字列だけを実行できるので、usingっぽいところだけを適宜実行すればOKです。

もうちょっと実践的なことをする

ファイルの退避処理

例えば、C:\TMP配下の.txtファイルをC:\TMP\backにタイムスタンプ(yyyymmdd)をつけて格納する、みたいな処理。

C:\TMP
│  fuga.txt
│  hoge.txt
│  piyo.png
│
└─back

これだけの処理ですがbatでやろうとすると結構面倒です。dirでtxtだけとってきて…batのforってどう書くんだっけ…日付の書式ってどう書くんだっけ…と嫌になってきます。

ここは.NETの力を借りましょう。どんどん借りましょう。

$baseDir = "C:\tmp"
$today = [datetime]::Today.ToString("yyyyMMdd")

foreach($file in (dir ($baseDir + "\*.txt"))) {
    
    # バッククオートを使うと改行できる
    $destFile = $baseDir + "\back\" + [System.IO.Path]::GetFileNameWithoutExtension($file) `
                    + "_" + $today + ".txt"

    copy $file $destFile
}

インテリセンスを使いつつ大体3分ぐらいで書けました。

また、当然のことですがPowerShellではパスが通ってるコマンドならいくらでも使用可能です。(dirとかcopyとかmoveとかはPowerShellのaliasで色々構文が変わってしまっていますが…。)コマンドの構文が思い出せなかったら.NETのAPIでやっちゃえばいいです。

それに加えて制御構文としてforeachswitchwhileなんかも当然のように使えます。もうbatを使う理由なんて一つもないですね。

もういっそ全処理をAdd-Typeでぶちこむ

ここまで読んでも「いやでもやっぱPowerShellクソ面倒でしょ。C#最高でしょ。」と思った人にオススメの方法があります。

PowerShell ver. 2から追加されたAdd-Typeと言うコマンドレットがあるんですが、.NETのDLLやソースをPowerShellで使えるようにしてくれます。コードをインラインで書いてもOKです。

# 文字列を@でくくるとヒアドキュメントになる
Add-Type @"
using System;

public class Test {
    public static void Exec(string arg) {
        Console.WriteLine(arg);
    }
}
"@

[Test]::Exec("hello world")
# => hello world

「やりたいことを全部C#で書く⇒PowerShellでAdd-Typeする⇒適当に呼び出す」とするだけでPowerShellの記述は、まぁおおよそ3行ぐらいですみます。やりましたね!

ちなみにこれ、-Languageを指定することでVB.NETでもいけます。VBおじさんにも優しい!やりましたね!

Add-Type -Language VisualBasic @"
Public Class Test
    Public Shared Sub Exec(ByVal args As String)
        System.Console.WriteLine(args)
    End Sub
End Class
"@

[Test]::Exec("hello world")
# => hello world

また、なぜかJScriptも読み込めます。何の因果かJavaScriptを習得してしまったWebデザイナーにも優しい!やりましたね!

$obj = (Add-Type -Language JScript -MemberDefinition @"
    static function exec(args) {
        // 流石にJScriptでConsole.WriteLineは無理っす…。
        return args
    }
"@ -Name "Test" -PassThru)[1]

Write-Host $obj::exec("hello world")
# => hello world

JScriptの例で-MemberDefinitionなるものを使いましたが、これを使えばC#でもいちいちクラスの宣言等が不要になります。

$obj = Add-Type -MemberDefinition @"
public static void Exec(string arg) {
    Console.WriteLine(arg);
}
"@ -Name "Test" -PassThru

$obj::Exec("hello world")
# => hello world

更にコードが短くなりました!もう怖いものなしですね!どんどんC#書きましょう!

まとめ

中々PowerShellおじさんに怒られそうな内容になりました。っていうか内容がペラッペラなので、何か思いついたらどんどん追記していきます…。

ともかく、PowerShellの文法をほとんど知らなくてもここまでやりたい放題できるので、ちょっとしたスクリプトをbatなんてゴミで作るぐらいならどんどん活用していきましょう。

参考

【Git】最低限やっておきたい.gitconfig

前書き

個人用メモなので他の人がどうしてるのかは知りませんが。復旧したり新しい環境で再設定したりするのが結構だるいんですよね…。

なんだか最近こんな記事ばっかりですね。

aliasで強制的に--no-pagerをつける

いきなり.gitconfigとは全く関係無いですが、pager使いたかったら自分で指定する方がストレスフリーなのでaliasを設定しておきます。

私はNyaosを仕事でもプライベートでも使っているので_nyaに記述。コマンドプロンプトを使ってる?知らんがな。

alias git=git --no-pager

前提知識

Gitのconfigファイルは三種類あります。どれか一つだけ修正して「なんか動かねーぞ!」と慌てる前にgit config --listを使って覚えのない設定で上書きされていないか確認しましょう。

git configでのオプション場所
--system (Gitがインストールされているディレクトリ)\etc\gitconfig
--global %USERPROFILE%.gitconfig
--local リポジトリの.git内のconfig

また、どんな設定ができるかはここに書いてありますが、正直読んでも全然わかりません。

systemレベルの設定

editorをvimにしたりとか、diffツールWinMergeにしたりとか。後はgrepにcolor設定したりとか。

alias以外はデフォルト以上のことはしないようにします。面倒だし。

[core]
    symlinks = false
    autocrlf = false
    editor = vim
[color]
    diff = auto
    status = auto
    branch = auto
    interactive = true
    grep = auto
[pack]
    packSizeLimit = 2g
[help]
    format = man
[http]
    sslCAinfo = /bin/curl-ca-bundle.crt
[diff]
    tool = WinMerge
    guitool = WinMerge
[difftool "WinMerge"]
    prompt = false
    path = C:/Program Files/WinMerge/WinMergeU.exe
    cmd = \"C:/Program Files/WinMerge/WinMergeU.exe\" -e -ub -dl \"Theirs Files\" -dr \"Mine  Files\" \"$REMOTE\" \"$LOCAL\"
    trustExitCode = false
[rebase]
    autosquash = true

aliasはこんな感じ。

[alias]
#各短縮形
st = status
cm = commit
br = branch -a
ad = add
co = checkout
wc = whatchanged
sh = show
ft = fetch

#オレオレ便利コマンド
diffd = difftool -d
cancel = reset --soft HEAD^
history = log --graph --date=iso --pretty=format:'%Cgreen%h %cd %Cblue%cn %Creset%s'
stat = log --stat
unstage = rm --cached
merged = branch --merged
no-merged = branch --no-merged

globalレベルの設定

最低限userだけ入ってればいいでしょみたいなスタンス。

色んな人が使う端末ならsystemの大部分はこっちに持ってきた方がいいんでしょうけど。

[user]
    name = tumbling-dice
    email = xxxxx@gmail.com

localレベルの設定

好きにしたまえ。

後書き

メモでした。

【VSCode】WindowsでVisual Studio CodeをそこそこまともなC#開発環境にするまでの手順まとめ

2018/11/22追記

この記事は3年以上前に書かれたものです。

現在では最早何の役にも立たない記事ですので、お帰りください。

前書き

超絶お久しぶりです。最近はくっそ忙しいです。忙しすぎて趣味的なコードを書く暇もありません。最近白髪が生え始めました。実績解除ですね。

さて、お仕事で使っているPCがあまりにもクソスペックすぎることは以前お話したんですが、最近わけあってVisual Studio 2013 ExpressをインストールしようとしたらHDD容量が足りないとか言う2015年とは思えない理由でダメでした。まぁ空き容量が2GBしかないし。.NET Framework 4.5.2 Developer Packすら入らないし。

そこで最近登場したVisual Studio Code、あれを使ってみようかなと。あわよくばScriptCsのコードもバリバリ書けるIDEにしておきたいなと思ったので、そのために準備した内容を書き留めておきます。

まぁなんと言うかですね。Windowsで無理に使うぐらいならVisual Studio 2015なりなんなりを入れた方が100倍便利です。現状だとC#デバッグすらできません。準備も結構大変です。私のようにやむにやまれぬ事情があるか、とりあえず使ってみたい人向けです。

Visual Studio Codeのインストール

公式サイトから落としてきてください。

Windows版だとC:\Users\{username}\AppData\Local\Code内に本体が置かれます。普通にProgram Filesに置いてくれよ…。

(2015/11/27追記)v0.8.0からインストール先を選べるようになりました。

Node.jsのインストール

Visual Studio CodeのインテリセンスはOmniSharpと呼ばれる技術で動いています。これはNode.jsを使ってローカルサーバを立て、そのサーバに対してPOSTするとRoslynが解析して使用可能な候補を返すと言う、理論上どんなエディタでも使用可能な仕組みです。

(2015/11/27追記) OmniSharp自体がサーバとしての機能を持っているのでNode.jsは関係ないです。(最近OmniSharpで遊び始めて気が付いた)

そのため、Node.jsがないとどうやってもインテリセンスが動かない…ってことは多分ないんですが(一応node.exeも同梱されてるし)、npmから色々なパッケージを持ってくることで開発が更に捗るので、インストールしてなかったらインストールしてきましょう。

インテリセンスを使うための準備

Visual Studio CodeでOmniSharpが起動する条件は以下の二つのどちらかを満たしている場合のみです。

  • ワーキングスペース内に*.sln(と、*.csprojとか*.vbprojとか)があり、Visual Studioがインストールされていること。
  • ワーキングスペース内にASP.NET 5用のproject.jsonがあること。

と言うわけで、Visual Studioを既にインストールしている方。おめでとうございます。既存のプロジェクトをVisual Studio Codeで開き、15~30分ほど遊んだ後、普段から使っているVisual Studioに戻りましょう。

多分、本当はVisual Studioなしでもどうにかすれば動くとは思うんですが、そもそもソリューションファイルを頑張って自作すること自体が恐ろしく面倒ですし、自分でシコシコとcsprojを書くのはあまりにも苦痛です。

ASP.NET 5のproject.jsonの方は比較的準備が簡単なので、今回はこちらの解説をしていきます。

ASP.NET 5の実行環境を整える

Visual Studio CodeでASP.NET 5を使うためのドキュメントがあるので、基本的にはこれを読んで一通りやればOKです。一応要点だけ解説します。あくまで要点なのでちゃんと元ドキュメントは読みましょうね。

まずはDNXをインストールします。これは.NET Execution Environmentの略で、その名の通り「.NETの実行環境」です。マイクロソフトが頑張ってMacLinuxでも.NET Frameworkで書かれたwebアプリケーションを動かせるようにしてくれました。もちろんWindowsでも動きます。

ASP.NETGitHubインストール手順があるので、黙々とインストールしてきてください。Upgrading DNVMと書かれていますが、後で諸々全部ついてくるのでご安心を。ちなみに「Visual Studio 2015をインストールするのが一番早い」とのことです。そっすか。

DNVMのパスが通っていることが確認できたらdnvm upgradeを実行しましょう。これにてDNXのインストールは完了です。

空プロジェクトをコマンドラインで作成できるようにする

次のステップです。ASP.NET 5の空プロジェクトをコマンドラインで生成するための諸々のツール・モジュールをnpm経由でインストールします。

ドキュメントにもあるように、以下のコマンドを実行するだけです。普段からNode.jsをバリバリ使ってる人は既にインストールしてそうなものもあるので適宜欲しい物を取ってきて下さい。

npm install -g yo grunt-cli generator-aspnet bower

ちなみにyoことyeomanWindowsだとyodoctorなるものが引っかかってインストールできないことがあるみたいなので、ダメだった場合はGitHubから適当にcloneしpackage.jsonから下記記述をまるっと消してしまいましょう。

「Gitなんか入れてねぇ」とぬかす人もいるかもしれませんが、Bowerを使うためにどのみち必要なのでこれを機にインストールしてきてください。

"scripts": {
        "test": "grunt",
        "postinstall": "node ./scripts/doctor",
         "postupdate": "node ./scripts/doctor"
},

消し終わったらコマンドプロンプトでカレントディレクトリをyoのプロジェクトに移した後、npm i -gを実行すればOKです。

とりあえず空プロジェクトを作る

DNXとyoとgenerator-aspnetをインストールしたらやっと準備完了です。空プロジェクトを作りましょう。

と言ってもコマンドプロンプトからyo aspnetと叩くだけです。後はConsole ApplicationかClass Libraryあたりを選択し、自動生成されたディレクトリでdnu restoreを実行すれば不思議な力によって謎のパッケージがNuget経由でインストールされ、なんだかよくわからないjsonが新たに生成され、Visual Studio Codeでそのディレクトリを開くとOmnisharpが動くようになっているはずです。お疲れ様でした。

project.jsonの中身を書き換える

と、それだけで済めばよかったんですが、もう一手間かけないといけません。

yo経由でClass Libraryのプロジェクトを作った場合、最初のproject.jsonはこんな風になっています。

{
    "version": "1.0.0-*",
    "dependencies": {},

    "frameworks": {
        "dnx451": {
            "dependencies": {}
        },
        "dnxcore50": {
            "dependencies": {
                "System.Runtime": "4.0.20-*"
            }
        }
    }
}

これをとりあえずこうします。

{
    "version": "1.0.0-*",
    "dependencies": {},

    "frameworks": {
        "dnx451": {
            "frameworkAssemblies": {
                "System": "",
                "System.Core": "",
                "System.Xml.Linq": "",
                "System.Data.DataSetExtensions": "",
                "Microsoft.CSharp": "",
                "System.Data": "",
                "System.Xml": ""
            }
        }
    }
}

上記のように変更した後、もう一度dnu restoreしましょう(コマンドパレットでrestoreと入力してもOK)。今度こそお疲れ様でした。これであなたはようやくまともな開発環境を一つ手に入れました。

project.jsonの役割と参照設定

本筋から大きくそれてしまうのですが、今後もproject.jsonはメンテしていくことになるので、簡単に解説しておきます。詳しい情報はドキュメントにたくさん書いてあるので一読しておきましょう。

project.jsonはcsprojとほぼ同様の内容を記述することができます。有名所で言えば参照設定、ビルドイベントとかですね。

実はrestoreコマンドを実行したdnu(DNX Utility)にはcsprojをproject.jsonに変換するコマンドも用意されていますが、Visual Studioをインストールしないと手に入らないようなMSBuild.exeを使うらしいので特に説明しません。

今回何を消して何を追加したかはこの辺が参考になると思います。

がっつり削除したdnxcore50の部分は、物凄く雑に言うと、「OSを問わずどんな環境でも動かすために必要なassemblyとそのバージョン」です。対してdnx451frameworkAssembliesは「GACに登録されているであろうassembly」です。本当に超絶雑な説明なので鵜呑みにしないように。

dnxcore50で使えるライブラリは、現状、かなりの制限があります。(Webアプリケーションで使うって意味では必要十分なんでしょうが。)

Visual Studio Codeくんはdnxcore50dnx451の両方でコンパイルできないと知ると「dnxcore50の方で参照設定が足りてないと思うんですけど(名推理)」と容赦のないエラーを吐き出すため、もういっそdnxcore50は定義しなくていいです。dnx451だけにします。ついでに普通にConsole ApplicationやClass Libraryのプロジェクトを作った時に定義される参照設定を入れておきます。

ただこのままだとyo aspnetする度にproject.jsonを直す必要があるため、generator-aspnetのtemplates内にあるproject.jsonも適当に直しておきましょう。

「自分で作ったDLLは参照設定に入れられないの?」と思った人もいると思います。一応できますが、プロジェクトのNugetパッケージ化が必要です。

後はdependencies内に名前とバージョンを書けば適当にNugetから取ってきてくれます。例えば、SgmlReaderの最新版を使いたかったら、こんな感じです。

{
    "version": "1.0.0-*",
    "dependencies": {
        "SgmlReader": "1.8.11"
    },

    "frameworks": {
        "dnx451": {
            "frameworkAssemblies": {
                "System": "",
                "System.Core": "",
                "System.Xml.Linq": "",
                "System.Data.DataSetExtensions": "",
                "Microsoft.CSharp": "",
                "System.Data": "",
                "System.Xml": ""
            },
            "dependencies": {
                "SgmlReader": "1.8.11"
            }
        }
    }
}

フォルダ構成はこうなります。

(root)
│  .gitignore
│  Class1.cs
│  project.json
│  project.lock.json
│              
└─packages
    │  
    └─SgmlReader.1.8.11
        │  SgmlReader.1.8.11.nupkg
        │  
        └─lib
            ├─2.0
            │      SgmlReaderDll.dll
            │      
            └─4.0
                    SgmlReaderDll.dll

コンソールアプリケーションを実行する

dnx [path] runでコンソールアプリケーションを実行可能です。コマンドパレットにも登録されているのでわざわざコマンドプロンプトを開く必要はないです。

exeファイルにビルドとかはできません。dnuにビルドコマンドはあるんですが、dllファイルになってしまいます。

Visual Studio Codeからビルドできるようにする

dnu build [path]とすることで対象のプロジェクトをdllファイルにビルドできます。が、Visual Studio Codeにはこのコマンドが登録されていないので、自分で作ります。

コマンドパレットでtaskと入力し、「Tasks: Configure Task Runner」を選択しましょう。自動でワーキングスペース内にtasks.jsonが生成されます。

後はこんな風にしておけばOKです。

{
    "version": "0.1.0",
    "command": "dnu", 
    "showOutput": "always", // 出力内容を必ず表示
    "isShellCommand": true, // 外部のツールかどうかの設定
    "isBuildCommand": true, // ビルドコマンドフラグ これをtrueにするとCtrl + Shift + Bでビルドできる
    "args": ["build"]
}

このtasks.json、複数のタスクが登録できると思うじゃないですか。だって「tasks」ですよ?そんなもん100%できると思うじゃないですか。なぜか一つしか登録できません。gulpを使うとできるみたいなことが書いてありますが、その、なんていうか、何なんでしょうね…。

おまけ - フォントの変え方

デフォルトだと日本語フォントが中華フォントになってしまいます。流石につらぽよなので変えたいところです。まぁでも、日本語のコメントを入力したら突然OmniSharpが死んだりするので、そもそも日本語を書かないことをオススメしますが。

方法1:settings.jsonをいじる

メニューバーのFile -> Preferences -> User Settingsから変えることができます。

選択すると自動でsettings.jsonを開いてくれるので、こんな感じのものを書いて保存すればOKです。

// Place your settings in this file to overwrite the default settings
{
    "editor.fontFamily": "適当な日本語フォント"
}

方法2:native.main.cssをいじる

方法1だと全部日本語フォントになってしまいます。英数字はConsolasで、日本語は別フォントで、としたい場合は、大元のcssをいじるしかありません。

ここを参考にC:\Users\{username}\AppData\Local\Code\app-0.1.0\resources\app\client\vs\monaco\ui\workbench\native\native.main.css内のfont-familyを検索し、よきにはからって下さい。

勿論他の要素をいじることもできるので参考サイトのように自分だけのオタク臭い開発環境を整えるのも一興でしょう。ただまぁ、アップデートかかったら即死ぬと思いますが。

(2015/11/27追記) v0.5.0ぐらいから構成が変わってnative.main.cssが消滅しました。ただまぁ、cssで設定していることには変わりないので、自力で修正自体は可能です。

参考

【C#】今更ScriptCsを触ってみる

前書き

最近新しくお仕事用のPCを貰ったはいいんですが、こう、端的に言って、とんでもないクソスペックです。

Windows 7は別にいいんですが、32bitだし、メモリ1GBしかないし…。今どき1GBのメモリなんてExcel開いてるだけで枯渇しますよ。

まぁ開発用ではないので何だかんだで使えはするんですが、こんなクソスペックでちょっとIDEでも入れるかーなんてとても思えません。

でもちょっとしたI/O操作とかスクリプト組みたいよねーって気持ちは常にあるので、適当なスクリプト言語の環境を整えることにしました。

でもI/O操作を考えるとC#が一番楽なんだけどなぁ…Visual Studioをこいつで起動するのはなぁ…と悩んでいたところ、ScriptCsの存在を思い出したので、導入することにしました。

ScriptCsってなに?

Roslynちゃんの力をフルに使ってC#をそのままスクリプト言語のように扱えるようにしてしまった謎の実行環境です。

InfoQの記事がとてもわかりやすいので読んでおきましょう。

インストール方法

Download Zip Fileとか書いてあるんでそこを押したくなるんですが、これは罠です。GitHubのmasterブランチがドカンと落ちてきます。

インストールするにはChocolatey経由で落としてこいとのことです。雑ですね。

もう既にChocolateyをインストールしている人はこれで落としてきましょう。Chocolatey自体のインストール方法はこっそりと以前の記事に書いてあります。

ちなみに、Roslynを動かす関係上.NET Framework 4.5以上が必須です。

注意点

微妙にハマったところだけ先に紹介しておきます。

  • ScriptCSのカレントディレクトリはscriptcs.exeが置いてあるディレクトリではなく、scriptcs.exeを呼び出したディレクトリとなる。
    • I/O操作は勿論、#load(後述)で呼び出すスクリプトのパスにも関わってくるので注意が必要。
  • dynamicは使用できない。
    • そもそもRoslynが対応してないっぽい。
    • そのせいでDynamicObjectも使えない。折角のスクリプト言語っぽい言語仕様なのに…!

REPL

インストールし終わったらscriptcs.exeを引数なしで叩いてみましょう。REPLが起動するはずです。

C:\> scriptcs
scriptcs (ctrl-c or blank to exit)

> var message = "Hello, world!";
> Console.WriteLine(message);
Hello, world!
> 

usingもnamespaceもclassもMainメソッドも必要ありません。これだけで動きます。REPLでなく、ファイルに書きだしたものを読み込ませても当然動きます。Roslyn様々ですね。

スクリプトファイルの読み込み

引数にファイル名を渡してあげれば勝手に実行してくれます。拡張子はcsxが推奨されています。別にcsxじゃなきゃ読み込んでくれないわけでもないです。

ただまぁ、文字コードはBOMつきUTF-8にしておいてあげましょう。Roslynちゃんは渡された文字列を問答無用でBOMつきUTF-8としてパースします。

試しに先ほどのサンプルをtest.csxとして保存し、「scriptcs test.csx」と実行すればコンソール上に「Hello, world!」が表示されるはずです。

スクリプト内でのファイル読み込み

とりあえずこんなコードを用意しました。ファイル名は「Hoge.csx」です。

public class Hoge {
    public string Fuga {get; set;}
    public int Piyo {get; set;}
    
    public string Foo() {
        return "Foo";
    }
}

#loadを使うことでスクリプト内でこれを読み込むことが出来ます。ちなみにREPLだと簡単に変数の中身が確認できるので、printfデバッグがしやすいです…と言うか、それ以外のデバッグ方法がないです。

C:\> scriptcs
scriptcs (ctrl-c or blank to exit)

> #load "Hoge.csx";
> var hoge = new Hoge { Fuga = "fuga", Piyo = 1 };
> hoge
{
  "$id": "1",
  "Fuga": "fuga",
  "Piyo": 1
}
> hoge.Foo();
"Foo"
>

スクリプト内でのアセンブリの読み込み

#loadと同じ感覚で#rを使うことでGACに登録されているdllを読み込む事も出来ます。何か参照設定が足りてないな?と思ったら使いましょう。

これは例を書いても仕方ないので、GitHubのサンプルを読んでおいてください。

また、これを使うことで既存の資産であってもバリバリ呼び出すことが出来ます。GACに登録するのはちょっと面倒だけども。

[2015/02/22追記]別にGACに登録されている必要はありません。相対パスを指定してあげればdllを読み込んでくれます。

ちなみに以下のアセンブリは自動で読み込まれています。

  • System
  • System.Core
  • System.Data
  • System.Data.DataSetExtensions
  • System.Xml
  • System.Xml.Linq

また、以下のnamespaceは暗黙的にusingが指定されています。

  • System
  • System.Collections.Generic
  • System.Linq
  • System.Text
  • System.Threading.Tasks

「普通にコンソールアプリケーションを作る時の設定と一緒」と覚えておけば十分でしょう。

Nuget

ScriptCSはなんとNugetまで内蔵しています。ここにあるパッケージは全て流用可能です。

インストール方法も極めて単純です。例えばJson.NETであれば、Nugetのコマンドはこうなっているわけですが、

PM> Install-Package Newtonsoft.Json

そのまま以下の形に置き換えるだけです。

scriptcs -install Newtonsoft.Json

当然依存関係があればそれも一緒に引っ張ってきてくれます。

インストールしたパッケージは「scriptcs_packages」と言うディレクトリで管理されます。ここに保存されたものは#rも#loadも必要ありません。使いたい時にusingでnamespaceを指定すればOKです。

が、一つだけ注意しなくてはならないことがあります。scriptcs_packagesもscriptcs.exeを呼び出したディレクトリ(カレントディレクトリ)に作成/保存されますし、スクリプト内でもカレントディレクトリにscriptcs_packagesがなければそのパッケージを読み込みません。

Script Packs

ScriptCSで使用されることを目的としたパッケージ群であるScript Packsなんてものもあります。ほとんどがNugetで配布されているのでやはり簡単にインストールできます。

これらはScriptCs.Contractsを継承しており、Require<TScriptPack>()と言う形式で呼び出すことが出来ます。例を書くのが面倒なのでGitHubの例を読んでおいてください。

[2015/02/22追記]

起動時引数の設定方法

大事なことを書き忘れていました。ScriptCSでも起動時の引数を設定することができます。

先に引数の取得から説明しましょう。Env.ScriptArgsReadOnlyCollection<string>として入っています。ReadOnlyCollectionはIEnumerableを実装していないので注意しましょう。

サンプルコードとしてはこんなものでいいでしょう。test.csxとでもしておきます。

Console.WriteLine(Env.ScriptArgs[0]);

引数を渡すのはこんな感じです。

C:\>scriptcs test.csx -- test

簡単ですね。マルチバイト文字やスペースを含むような引数の場合はダブルクオーテーションでくくればOKです。

C:\>scriptcs test.csx -- "ほげほげ" "ふが ふが"

ちなみにREPLで起動する場合は引数を渡せません。なんでじゃ。

まとめ

と言うわけで、既存の資産のバリバリ使用しつつちょっとしたコードをガンガン書けるので中々に便利です。

「好きなエディタでC#を書けるよ!」を売り文句の一つにしていますが、ぶっちゃけそれは非常に辛いので実際にはCShellあたりで書くことになると思います。

C#が大好きすぎてスクリプト言語全般に死んで欲しい人は是非試してみてください。

pupを使ってコンソール上でスクレイピングする

curlとかwgetとか使っているといっそコンソール上でスクレイピングしたくなることがよくあります。

自分でパーサを書くのも面倒だし何かないかなと探していたらpupなるものを見つけました。

動作

標準入力 or ファイルの内容をCSS Selectorで検索、抽出し、標準出力に表示します。

つまり、パイプを通し放題なわけです。便利ですね。

出力形式は

  • HTML
  • テキスト
  • json

のうちどれか一つを指定することが出来ます。また、あるElementのあるAttributeの値だけを出力、なんてことも出来ます。

勿論、pupで出力した結果をパイプしてgrepしたりtrして更に加工してもいいでしょう。pupの結果をpupにパイプしたりしてもいいと思います。

インストール

Release Pageコンパイル済みの実行ファイルが置いてあります。

Go言語の環境がインストールされていればgo getで、Mac使ってるならbrewでもいいみたいです。

使い方

GitHubQuick StartExampleを見ておけば十分です。

出力形式の指定

Display Functionsと言うセクションに書いてあります。

  • text{} - 抽出したElementのテキスト
  • attr{attrkey} - 抽出したElementのattributeの値
  • json{} - 抽出したElementのjson

指定しなければHTML形式のまま出力されます。

attr{attrkey}を上手く活用すればXMLのパースもそこそこ容易に可能なので、コンソール上で動くRSSリーダーなんかも作れたりします。

オプション

オプション 省略形 動作
—color -c 出力結果を色付きで表示してくれる。
—file filePath -f filePathに指定したファイルを使用する。
—help -h ヘルプを表示する。
—indent count -i countに指定した数値の数だけインデントする。(html、jsonのみで有効)
指定しないとデフォルトのインデントが入る。
—number -n 出力された結果の番号を表示してくれる…らしいのだが、指定すると「そんなオプションはない」と怒られる。
ソースを見てみると確かにない。何だこれ。
—limit level -l level以上の要素を「…」として表示します。いっそ表示してくれないほうがありがたいんだが。
textも1レベルとしてカウントするので注意。
—charset charset N/A UTF-8EUC-JP以外のものを読み込ませる時に使うのだと思われるが、どんな値が指定できるのかよくわからない。
内部ではcharset.Lookupにそのまま値を渡しているが、これまたどんな値が指定できるのかよくわからない。
試しに「Shift-JIS」を渡したら上手く行ったので、常識の範囲内で指定してあげて下さい。
—version N/A バージョンを表示します。

まとめ

そんなわけで、pupを入れればちょっとしたスクレイピングならコンソールだけで簡単に出来てしまいます。

一々何らかの言語でパースしてた人は試してみてはいかがでしょうか。