質問: 例えば curlリリースページからリンクされているファイル `curl-7.61.1.tar.bz2.asc` をダウンロードしようとしたとき、 ``` curl -L -O \ https://github.com/curl/curl/releases/download/curl-7_61_1/curl-7.61.1.tar.bz2.asc ``` とすればカレントディレクトリに `curl-7.61.1.tar.bz2.asc` というファイル名でダウンロードされますが、このURLの末尾に `#/custom-named-file` を付与して ``` curl -L -O \ https://github.com/curl/curl/releases/download/curl-7_61_1/curl-7.61.1.tar.bz2.asc#/custom-named-file ``` とすると `custom-named-file` というファイル名でダウンロードされます。 これは何か公の仕様に則った挙動なのでしょうか(その場合何かこの仕様を調べるのに利用できる単語/キーワードはあるでしょうか)。 あるいはcurlの独自機能なのでしょうか。 --- (補足) 本件に疑問を持った発端は、 PowerShell 5.1で `WebRequest` を利用する場合も上記curlと同じような挙動を示すのに対し、 PowerShell Core 6.1.0 では そのようなURLを渡すとステータスコード400エラー(Bad Request)になるのを見つけたことからです(参考)。 --- 「正当」という言葉の意味が曖昧だ、というコメントを頂きましたので追記致します。 Web系開発者から見て、curlの今回の挙動は、当然そうなるだろうというものなのか、いやいやおかしいだろうというものなのかが知りたいです。 (そしてそう考える根拠がもしあるのなら、それも知りたいです) また本件について自分でも調べようとしたのですが、 `#/` を検索キーワードとして入力しても有用な情報が何も得られないので、もし呼び方があるのなら教えて下さい。 「補足」で触れていますが、PowrShell5.1では `#/name` を受け入れ6.1ではエラーとなる、という挙動に気付いたのが発端なのですが、 `#/name` ってcurlでちゃんと処理できてるじゃん(PowerShell6バグってんのかよ)...ん?そもそもこれって何なんだっけ?、というのが質問の根本です。
回答: せっかく私のコメントに関して追記していただいているので、無理にでも回答を書いてみるとこんな感じ。 まず、URL中の`#`の部分ですが、 に含まれる`#/custom-named-file`はFragmentと言うもの(RFCの本文中では *fragment identifier* と記されているが、構文規則には`fragment`とだけ書いてある)で、URIとしては構文上正しいものです。この例で言うとURIのPath部分が`curl-7.61.1.tar.bz2.asc`までになることはURIの仕様として規定されています。 (ちなみに上の_Fragment_のリンクの中身は`https://tools.ietf.org/html/rfc3986#section-3.5`と言うもので、この場合、`https://tools.ietf.org/html/rfc3986`で表される文書の中で`section-3.5`と言う識別子で表される特別の部分を表す書き方です。) 通常の使い方では`#/custom-named-file`の部分はサーバ側には送られないか、サーバ側では無視され、受信したリソース(今の場合はHTMLテキスト)のどの部分かを特定するのにブラウザ側で使われます。 ただし上記のRFC自体はFragmentの詳細な意味までは定めていないので、クライアント側がFragment部分を送信するかどうか、サーバ側が受信したFragmentをどう解釈するかは、使用するクライアント・サーバによります。(この辺り詳細な規定があるのか調べきれていません。) 従って、**使用するクライアント・サーバによっては、Fragmentの有無で取得されるリソースが変わってくる可能性があります**。curlの場合には(少なくともHTTPであれば)Fragment部分は送信しないようなので、この心配はなさそうです。 ただし、Fragment(あるいは`#/`のような`/`付きのFragment)が、下記の***the file part of the remote file***を表すと言う規定は(HTTP以外を探しても)存在しないでしょう。 ***これは何か公の仕様に則った挙動なのでしょうか*** コメントに書いたようにcurlの場合、「公の仕様」と言えるものはmanページくらいしかありません。 現在のcurlの`-O`オプションの記述はこうなっています。 > > ### -O, --remote-name > > > Write output to a local file named like the remote file we get. (Only > > the file part of the remote file is used, the path is cut off.) > > > The file will be saved in the current working directory. If you want > > the file saved in a different directory, make sure you change the > > current working directory before invoking curl with this option. > > > The remote file name to use for saving is extracted from the given > > URL, nothing else, and if it already exists it will be overwritten. If > > you want the server to be able to choose the file name refer to -J, > > --remote-header-name which can be used in addition to this option. If the server chooses a file name and that name already exists it will > > not be overwritten. > > > There is no URL decoding done on the file name. If it has %20 or other > > URL encoded parts of the name, they will end up as-is as file name. > > > You may use this option as many times as the number of URLs you have. > > > ***Write output to a local file named like the remote file we get. (Only the file part of the remote file is used, the path is cut off.)*** / ***The remote file name to use for saving is extracted from the given URL*** / ***There is no URL decoding done on the file name.*** という記述がありますが、これを「Fragmentにパスの最後っぽい内容があればそれをremote fileとする」という風に解釈するのは、無理でしょう。(もちろん明確にそうしない、とも取れない。) つまり「何か公の仕様に則った挙動」とは言えない、と言うことになると思います。 ***curlの独自機能なのでしょうか*** これもコメントどおりですが、現在の挙動が意図されたものかどうかがわかるような記述は見つけられませんでした。(数分間公式サイトをうろうろしただけですが。) と言うわけで、(意図して提供されている)「独自機能」と言うよりは、「現在の実装ではそうなる」と言うことだと思われます。 ***Web系開発者から見て、curlの今回の挙動は、当然そうなるだろうというものなのか、いやいやおかしいだろうというものなのか*** すでに上に述べたことでわかると思いますが、「当然そうなるだろう」と期待する根拠は「現在の実装がそうなっている」こと以外にはありません。ただし、「いやいやおかしいだろう」と言うものかどうかは人によるだろうと思います。(世間に流通しているシェルスクリプトなんかには、いろんなコマンドの「現在の実装」に基づく詳細動作に依存しているものはいっぱいあるでしょう。) 結論としては、ご自身で書かれているように「(現在の)curlのurlパース仕様を利用したハック技」と言えるだろうと思います。(ただ、便利ツールであるcurlが、「こんなのバグじゃないの?」なんて指摘を受けても、そこの実装が変更される可能性は低いと思いますが。) 私的には、curlには、ちゃんと出力先を示す`-o`オプション(わかっているとは思いますが、小文字の方です)があるんだから、素性のわからない`-O`と`#/name`なんて書き方を使わなくてもいいんじゃないの?と言う感じです。