Windows
curl
memo
PowerShell
wget

PowerShellでcurl, wgetを使いたい

背景

WSLでLinux環境が手軽に使えるようになったので、PowerShellとLinuxのコマンドラインを行き来する機会が多くなった。

そうなると、PowerShellで作業している時についcurl http://example.comのように入力してしまい勝ちだが、PowerShellは標準でcurlwgetInvoke-WebRequestコマンドレットをエイリアスとして割り当てているため、期待どおりの出力じゃなくて微妙な気分になる。

個人的にはInvoke-WebRequestが使いたいならそう書くよ!と思ったので、curlwgetについては標準のエイリアスを上書きしたいと思った。(ちなみにInvoke-WebRequestにはiwrという標準エイリアスがあるので尚更…)

設定系は次にやる時まで内容を覚えていない事が多いので、メモとして記録してみる。

Windows用のcurl, wgetをインストール

Chocolateyを使っているので、cinstでさくっとインストール完p了。

PowerShell(管理者)
PS C:\>cinst curl wget -y

個別に入れたい場合は、それぞれ以下から入手可能。
curl - Download
GNU Wget 1.19.2 for Windows

エイリアスの上書きのテスト

Set-Aliasコマンドレットで上書きしてみる。
Chocolateyでは%ChocolateyInstall%\binフォルダにShimを作ってくれるので、そこを参照する。
(個別にインストールした場合はインストール先のフルパスを指定する)

PowerShell
PS C:\>sal curl (Join-Path $env:ChocolateyInstall "bin\curl.exe")

salはSet-Aliasのエイリアス

が、これで実行してみたら以下のエラー

PowerShell
PS C:\> sal curl (Join-Path $env:ChocolateyInstall "bin\curl.exe")
sal : AllScope オプションをエイリアス 'curl' から削除できません。
発生場所 行:1 文字:1
+ sal curl (Join-Path $env:ChocolateyInstall "bin\curl.exe")
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : WriteError: (curl:String) [Set-Alias], SessionStateUnauthorizedAccessException
    + FullyQualifiedErrorId : AliasAllScopeOptionCannotBeRemoved,Microsoft.PowerShell.Commands.SetAliasCommand

どうやら既定のエイリアスがAllScopeで定義されているため、Localスコープのエイリアスとして上書きする事ができない模様。
AllScopeをオプションにつけて実行してみる。

PowerShell
PS C:\> sal curl (Join-Path $env:ChocolateyInstall "bin\curl.exe") -O AllScope
PS C:\> gal curl

CommandType     Name                                               Version    Source
-----------     ----                                               -------    ------
Alias           curl -> curl.exe

galはGet-Aliasのエイリアス

できた。

$Profileの作成

以上の手順だけだとセッションごとにやり直す必要があるので、プロファイルで設定を行うようにする。
Bashでいうところの~/.bash_profileとか~/.bashrcに相当するのがPowerShellだと$Profileで参照できるファイル。

※注意:ユーザーやホスト(ISE等)ごとに指定方法が異なるので、詳しくはこちらを参照。

notepad $profileとかで適当にエディタで開いて以下の内容で作成。

Microsoft.PowerShell_profile.ps1
#Alias
$aliases = @{
  curl = Join-Path $env:ChocolateyInstall "bin\curl.exe";
  wget = Join-Path $env:ChocolateyInstall "bin\wget.exe";
}
$aliases.GetEnumerator() | % {if (Test-Path $_.Value) {sal $_.Key $_.Value -O AllScope}}

後で同様の追加がし易いようにハッシュテーブルに「エイリアス名=コマンドのファイルパス」形式で定義してみた。
コマンドがあれば追加するエイリアスをセットする。

ファイルを上書き保存し、PowerShellの開き直してgalで確認→OK。

おまけ

当初、

PowerShell
$aliaese | % {...}

でやってみたらうまく値が取れなくて悩んだが、PowerShellのハッシュテーブルは明示的にGetEnumerator()を付けないと列挙できないらしい。(知らなかった…)
参考:PowerShellのHashtableがコレクション扱いされない話 - しばたテックブログ

C#脳だとハマるポイントかも。

追記(2017-11-19)

curl, wgetコマンドがパスの通った場所にインストールされているのであれば、

Microsoft.PowerShell_profile.ps1
#Alias
del alias:curl
del alias:wget

として単純にエイリアスを削除するだけでも良かった。
こっちの方がシンプル。

ただパスでの解決に頼っちゃうと、cygwinとかで同名のコマンドがインストールされたら意図せず呼ばれるプログラムが変わる可能性がある。(パスの指定順に気をつければ良いとは言え)

curlやwgetみたいに同じ挙動のプログラムならあんまり問題ないんだけど、ちょっと気持ち悪い。
それが嫌なら、どっちにしろ同名のエイリアスを作る処理を足さないといけないので、あんまり変わらないかな。

追記(2017-12-20)

curlについて、tarと共に Insider Build 17063 から標準搭載されるそうです。
Insider Buildはまだ試してませんが、PowerShellの標準aliasも無くなるかな?

Tar and Curl Come to Windows! | Virtualization Blog

追記(2018-05-04)

April 2018 Updateを適用後に確認したところ、Invoke-WebRequestへのエイリアスとしてcurlが残っていました。(wgetも同様)
コマンドプロンプトも使う人は注意が必要ですね。