curl, wget そしてInvoke-WebRequestの違い

#背景
今日はインターン先の会社で勉強会がありました。その中で唯一自分が発言することができたトピックがこの3つのコマンドについてです。これらはどれもコマンド上からファイルをダウンロードする際によく使用されるコマンドです。しかしながら、これらは使ったことがあるにしてもそれぞれの違いや実際の機能をよく知らなかったため、今回調べてまとめることにしました。
また、どれも広範な機能を持つため、基本的にはファイル取得という面で見ていきます。

#Invoke-WebRequest
なぜ一番最初にPowerShellなどという誰もがよく知らないシェルについて記述するのか疑問に思われる方が大半でしょうが、それは僕が一番最初に触れたプログラミング言語がPowerShellだからです。そしてあまり人気がなく、よく知っている人が少ないために僕でもイキれるからです。PowerShellに自信ニキ(自信があるとは言っていない)なのです。

本題に戻ると、Invoke-WebRequestはPowerShell3.0から導入されたコマンドレットです。aliasとして、curlとwgetが設定されていることからもこれらを意識していることは明らかです。もっとも、これらとPowerShellのコマンドレットとは考え方からして違うと思うので、同じ書き方、動き方は期待できないと思います。

```PowerShell

> Get-Alias | Where-Object {$_.Definition -eq "Invoke-WebRequest"}

CommandType     Name                                               Version    Source                                   
-----------     ----                                               -------    ------                                   
Alias           curl -> Invoke-WebRequest                                                                              
Alias           iwr -> Invoke-WebRequest                                                                               
Alias           wget -> Invoke-WebRequest                                                                              

```

*設定されているエイリアスを表示しました、iwrはInvoke-WebRequestの略ですね。初めて知りました。

公式ヘルプによれば、Invoke-WebRequestの行うことは

>Gets content from a web page on the Internet

ネットからとってくるってことですね。

とりあえず、ネットから何らかのファイルを取得しましょう。今回は最高裁判所から、砂川事件の判決全文(PDF形式)をとってきます。

http://www.courts.go.jp/app/files/hanrei_jp/816/055816_hanrei.pdf

```PowerShell
Invoke-WebRequest -Uri http://www.courts.go.jp/app/files/hanrei_jp/816/055816_hanrei.pdf -outfile $env:USERPROFILE\Downloads\sunagawa_hanrei.pdf
```
このように、Invoke-WebRequestコマンドレットでは、まず対象のUriを指定し、outfileオプションの先にパスとファイル名を指定することで、ファイルの保存ができました。


#curl
さて、いよいよおなじみのcurlについてです。一番よくつかわれているのはこれなのではないでしょうか。
まず一番最初に目につくのは、対応するプロトコルが多い点です

以下は公式？からの引用です。

>Supports...

>DICT, FILE, FTP, FTPS, Gopher, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMB, SMBS, SMTP, SMTPS, Telnet and TFTP. curl supports SSL certificates, HTTP POST, HTTP PUT, FTP uploading, HTTP form based upload, proxies, HTTP/2, cookies, user+password authentication (Basic, Plain, Digest, CRAM-MD5, NTLM, Negotiate and Kerberos), file transfer resume, proxy tunneling and more.

めちゃくちゃ多いですね、後述しますがwgetは3種類です。

ここでは、manコマンドでcurlについての説明を見てみました

>curl  is  a  tool  to transfer data from or to a server, using one of the supported protocols...

データをサーバーから(へ)移すツールですよということですね。
以下にも続きますが、manコマンドはPowerShellのget-helpよりも親切で好きです。

再度、curlで砂川事件のpdfファイルをダウンロードしてみます。

```zsh
>curl "http://www.courts.go.jp/app/files/hanrei_jp/816/055816_hanrei.pdf" -o ~/Downloads/sunagawa_hanrei.pdf
```

oオプションを指定した場合、自分でファイル名を決めることができます。一方でOオプションを指定した場合は、uriからファイル名が決まります。

#wget
wgetは先程も述べましたが対応しているプロトコルがHTTP,HTTPS,FTPだけです。

またmanに頼ると...


>GNU Wget is a free utility for non-interactive download of files from the Web.  It
       supports HTTP, HTTPS, and FTP protocols, as well as retrieval through HTTP proxies.

webからファイルをダウンロードするということですね、説明の内容としてはInvoke-webRequestに近しいもののように思えます。

```zsh
>wget "http://www.courts.go.jp/app/files/hanrei_jp/816/055816_hanrei.pdf"
```

たったこれだけでuri末尾のファイル名と同じpdfファイルが配下にダウンロードされました。この点いちいちオプションを指定しなくても良いwgetが一番便利です。
では出力先のPATHとファイル名を指定したいときはどのようにすればよいでしょうか

```zsh
>wget  "http://www.courts.go.jp/app/hanrei_jp/detail2?id=55816" -O ~/Downloads/sunagawa_hanrei.pdf
```
Oオプションです、curlと逆なので混乱しますね

wgetには再帰オプションという特色的なオプションがあります。これを指定することで、配下にあるすべてのファイルをダウンロードできます。
先程の最高裁のページからこのｒオプションを使用してwgetしたところ、大量のファイルがダウンロードされ、怖くなったので途中でやめました。

```zsh
>wget -r "http://www.courts.go.jp/app/hanrei_jp/detail2?id=55816"
```

このような事態を避けるために、wgetには取得する階層のレベルを指定するlオプションがあります。


```zsh
>wget -r -l 1 "http://www.courts.go.jp/app/hanrei_jp/detail2?id=55816"
```

lの後の数字が何階層下までダウンロードするかを決定します。

#まとめ
curl、wget,そしてInvoke-WebRequestについて、その一端を少し調べて何度かコマンドを叩きながら理解を深めようと思ったら、思ったよりも深みにハマり脳みそが混乱するような文章をかいてしまったなと思います。しかしながら、wgetとcurlはその機能において少々異なること、PowerShellのコマンドレットはちょっと混ぜて語るべきではないことがいまわかりました。そもそも、curl,wgetのような異なるものをエイリアスとして同じコマンドレットに登録しているのはなんか違うのでは？と思います。もちろんPowerShellはとても便利なツールなので大好きなのですが。
最後に、この記事には多分に間違いや認識不足な点が多くあると思うので、指摘してくださると幸いです。あと、砂川事件判決は重要判例なので読んで損はないと思います。

__続編__
__Windows10にcurlあるじゃん！という話__
https://qiita.com/tatsuki1112/items/c230bf3ca4c7e654a10a
☝続編を書きました

#参考
curl公式
https://curl.haxx.se/
wget公式
https://www.gnu.org/software/wget/
MS公式
https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/invoke-webrequest?view=powershell-6
curlとWgetの比較
https://postd.cc/curl-vs-wget/
最高裁判所
http://www.courts.go.jp/app/hanrei_jp/detail2?id=55816