コマンドレットのパラメータを列挙してみる。2017の10日目です。PowerShellはオブジェクトを扱うシェルですが、別にテキストデータを扱えない訳ではありません。PowerShellで取得したデータをテキストファイルとして保存したり、スクリプトで用いるデータをテキストファイルで保存しておくことは日常的に行われることだと思います。PowerShellで扱うデータはオブジェクトであり、テキストファイルは文字通り文字列であることから、コマンドレットを用いる等、何らかの手段で変換が必要になります。テキストデータ形式にも様々な種類があり、それぞれメリット、デメリットが存在します。今回の記事では、PowerShellで用いるデータを保持しておく際のテキストデータ形式について比較をしてみます。プレーンテキストプレーンテキスト、すなわち書式なしのテキストファイルです。シンプルな使い方をする場合、文字列配列の各要素に含まれる文字列が、テキストファイルの1行と対応します。UTF8$linesは文字列変数です。理由がなければ文字コードはUTF-8で良いと思います。UTF8Add-Contentは実行のたびにファイルを開いて、書き込んでから閉じるという動作をするので、1行ずつforeachで実行するのはNGです。UTF8)メリット文字列配列をテキストファイルに書き出すのは多分これが一番楽だと思います。書き出したデータは人間にも読みやすい。デメリット文字列だけを保存しておきたいというケースがそもそも少ない。CSVコンマ等の特別な文字で区切り、1行あたりに複数のデータを保存できる形式です。PowerShellのコマンドレットで扱う場合、オブジェクトが持つプロパティがヘッダ列名に対応します。各行にオブジェクト配列1要素のプロパティ値が、カンマ区切りで保持されます。Default$objectsは任意のオブジェクト配列です。必要であればSelect-Objectコマンドレットを併用して、プロパティを絞り込みます。文字コードはExcelでそのまま読み込み/書き出しができるDefault(日本語環境ではShift_JIS)がお勧めです。Defaultメリットオブジェクトのプロパティ値が、すべて数値あるいは文字列で表現できる値を持つ場合に最も適合する。人間にも読みやすく、ある程度は編集もできる。デメリットオブジェクトのプロパティが、数値と文字列以外のオブジェクトである場合、すなわち、階層構造を持つデータの保存には適さない。数値も文字列として読み込まれてしまうので、数値として扱いたい場合は変換が必要になる。Export-CsvとImport-Csvで扱うCSVファイルはヘッダが必須。ヘッダなしのCSVファイルが既にあって、それを読み書きするという用途には適さない。(できなくはないが)書き出し時の列順を制御することができない。PowerShellで書き出したCSVを、列順が固定であるとの想定である他のプログラムで読み込むことは基本NG。書き出し時、1つ目の要素に存在しないプロパティは、2つ目以降では存在しないものとして扱われる。同種のオブジェクトで構成される配列なら通常は問題ないのだが、要素によって動的に追加されるプロパティがあったりなかったりすると厄介。(ADでありがち)JSONJavaScriptのような表記でデータを保持するデータ形式です。データの受け渡しに様々な言語で利用できます。APIでもよく利用されます。PowerShellではv3からJSONを扱うコマンドレットが提供されています。ConvertFrom-JsonメリットCSVと異なり、階層構造を持ったデータでも扱える。CSVと異なり、数値は数値型のまま読み書き可能。(整数値はint、小数値はdecimal)人間にもまぁまぁ読めるし、頑張れば編集できなくもない。デメリット-Depthパラメータによりプロパティを展開する階層の深さを指定はできるが、プロパティに応じて深さ指定を変化させるというようなことはできない。基本的には、自分で構築したPSCustomObjectを使うか、JSON化する前に自分で元オブジェクトを整形しておく必要がある。直接ファイルに書き出し、追記、ファイルから読み込みするコマンドレットはない。実は細かい話をしだすと色々と罠があります...。CLIXMLPowerShellではPSリモーティング等、プロセス間でオブジェクトのやり取りを行う際に、CLIXML形式を介してシリアライズ/デシリアライズが実行されます。シリアライズ対象によっては、完全に元のクラスのオブジェクトに復元されます。(復元されないオブジェクトにはクラス名にDeserialized.との接頭辞が付与され、プロパティ値のみ復元される)ユーザーもコマンドレットを用いて、任意のデータをCLIXML形式でシリアライズし、XMLファイルとして保存することができます。file.xmlメリット元のオブジェクトの構造、プロパティ値と型情報を含めてほぼ完全にテキストファイルに保存できる。復元したオブジェクトはプロパティ値を参照できるのはもちろん、オブジェクト全体が完全にデシリアライズされ、元の型に戻った場合には、メソッドを実行することも可能。元の型に戻らず、Deserialized.との接頭辞が付いた状態でも、コンソールに表示する場合は元の型のフォーマットが使われるので見やすい。デメリットすべてのオブジェクトが元の型に戻せるわけではない。戻せるかどうかは確認が必要。人間が読み書きするようなものではない。ちなみに、ConvertTo-Xmlという似たようなコマンドレットがありますが、出力形式はCLIXMLではない上、復元の手段もなく、かといって別に読みやすいXMLというわけでもなく、正直何のために使うのかよく分かりません(適切なxsltでも用意すればいいのかな?)。ConvertTo-Htmlの方が使えそうです。psd1psd1は「PowerShellデータファイル」で、モジュールマニフェストやローカライズデータに使われるファイル形式です。コメントなど基本的な言語要素のみ使用可能です。5.0以降ではImport-PowerShellDataFileコマンドレットを用いて、任意のpsd1ファイルのデータを読み込み、変数に格納することが可能です。書き出し書き出し用のコマンドレットはありません。読み込み例えば以下のような内容をbackup_setting.psd1として保存しておきます。ルート要素は必ず連想配列にします。"0:00"}なお、dataセクションで全体を括ってもいいですが、psd1で許容される言語要素はdataセクションより更に制限がきついので、敢えてしなくてもいいんじゃないかと思います。このファイルは以下のように読み込めます。backup_setting.psd1$settingには連想配列が格納され、以下のように値が参照できます。$_.To}メリットPowerShellの構文でデータを記述できる。通常のps1ファイルを呼び出すのとは異なり、式の評価やコマンド実行などはされない分、セキュアである。配列と連想配列の組み合わせにより、JSONライクな階層構造を持てる。JSONとは違い、コメントが入れられる。デメリット記述できるデータはプリミティブなものだけ。スクリプトから書き出すためのコマンドレットがない。一応、下位バージョンでやる方法はあります。まとめPowerShellで扱うデータをテキストファイルとして保存する際には、各テキストデータ形式の特性を理解し、メリット、デメリットを踏まえて選定する必要があります。当然ながらテキストファイルに保持することが不適切なデータもありますので、そこは注意してください。(画像データを敢えてBase64とかでエンコードしてテキストファイル化する意味があるのか、とかですね)個人的には...ちょっとした作業ログ等を記録しておきたい→プレーンテキスト.NETオブジェクトの一部のプロパティだけ抜き出してファイル化したい→CSV自分で構築したPSCustomObjectをファイル化したい→JSON.NETオブジェクト全体をファイル化したい→CLIXMLスクリプトで使う設定データを用意したい→psd1みたいな感じでなんとなく使い分けていると思います。psd1はまだ採用例はないですが...。今回はビルトインのコマンドレットで扱えるもののみ取り上げましたが、他にもyaml等のテキストデータ形式が存在し、有志によるモジュールを用いて扱うことが可能です。2017の1日目です。Calendar、今年も始まりました。ここ数年は私がトップバッターを務めさせていただいて、1年間のPowerShell界隈の出来事をさくっとまとめてみています。Editionが各々正式版としてリリースされ、さらにはPowerShellがオープンソース化、マルチプラットフォーム展開を始めるという大きな変革があった年でした。今年2017年は昨年ほど大きな変化はないとはいえ、昨年のOSS化からのマルチプラットフォーム展開を着実に進行させた年だと言えると思います。以下、いくつかトピックを紹介します。Updateにも同梱されました。R2)のためのものです。Win10/2016に同梱のPester(テストフレームワーク)やPSReadline(コンソール入力支援)についてはWMF5.1には含まれていないので、別途PowerShellGetでインストールするのがお勧めです。ShellではまずBashがサポートされていましたが、今年9月にPowerShellもサポート(まだプレビューですが)されました。PowerShellのコマンドが使え、AzureのリソースにAzure:ドライブを介してアクセスすることが可能です。5.1であることはちょっと念頭においておいたほうがいいかもしれません。PowerShellの全機能がサポートされてないからだと思うんですが、今後に期待ですね。Codeの正式版(1.0)が5月に公開されました。現時点での最新バージョンは1.5.1となっています。ISEの方が多機能だったようにも思いますが、今はもう完全にISEの機能を追い越したんじゃないかと思います。Analyzer、テストフレームワークのPester、プロジェクト管理機能を提供するPlasterなどが統合されており、本格的な開発環境となっています。Coreの開発が各々可能です。VSCodeの開発に注力されることになります。ISEはとにかく標準添付である(GUI有効ならサーバーOSでも動く!)という強みがあり、シンプルなスクリプト記述であればそこそこ便利に使えるので、これからもシチュエーションに応じて使い分けて行けば良いのかなと思います。Candidate)となりました。6.0.0のGAリリースは来年1月になるそうです。OSS化直後からRCに至るまでの変更点は多岐に渡り、とても一言で説明できるものではないですが、ポイントとしては以下の3点に集約されるんじゃないかと思います。5.1のコードそのままであったと言ってよいかと思います。10年以上増改築が繰り返されたコードが突如、全世界に公開されたわけです。コミュニティの力でバグや変な仕様といった問題点が洗い出され、どんどん修正されていきました。不足していると思われる機能はどんどん追加されました。既存コマンドレットのパラメータが増えるというパターンが多かったように思います。特筆すべきは、破壊的変更であっても妥当性があれば躊躇せずに取り入れていったことかと思います。Coreでは細かいところで非互換性が色々出ていますので、移行の際には注意を要します。5.1なので、Windowsでしか動作しない部分が多々ありました。それをLinuxやMac環境でも動作するように多くの修正が加えられました。Edition相当のPowerShellをビルドすることが可能でした。Core」であることが明確にされました。CLR対応のコードのみとなりました。5.1に含まれているすべてのコマンドレットを網羅しているわけではありません。6.0には含まれておらず、α版の段階では実行も不可能(だったはず)でした。2.0がサポートされました。Coreでも実行可能になりました。PowerShellはどうなるのか、という話について。5.1については、今後もサポートライフサイクルに則り、重大なバグフィックスやセキュリティパッチ提供等のサポートは継続されます。PowerShellも同様です。Coreへと移行します。PowerShellとは無関係ということです。CoreがWindowsに同梱されるかどうかについては言及されておらず、今のところは不明です。以下は私見になります。Serverの管理はするが、Linuxとかは特に...というユーザーはこれからどうすべきか?という点は割と悩ましいところだと思います。Serverを管理するスクリプトが現時点であるなら、それを無理に今すぐCore対応にする必要はないと思います。現時点で今すぐCoreに移行すべき理由というのはとくに無いと感じます。Coreで追加、改善された機能はあるものの、Coreには無い機能もたくさんあるからです。PowerShell用に作れば良いのではないかと。OS付属のコマンドレットの動作は確実に保証されているわけですから。2016は半期に一度の大型アップデートで新機能が次々追加されていきます。Coreが含まれるようになったり、Coreのみ対応のコマンドレットが追加される可能性は無きにしもあらずなのではないかとも思います。Coreの状況をチラ見しつつ、未来に備えておく必要はあると思います。Windows10/Server2016の「次」も見据えて。それとPowerShellでWindowsもLinuxも面倒みていきたい、という野心がある方は、Coreを採用していくのがいいのではないかと思います。現状しばらくは茨の道ではあるとは思います。あとはスクリプトやモジュールを作成し公開する方は、より多くの環境で使われるように、可能であればCore対応を進めるのは悪くないんじゃないかと思います。Core構想とか、なにげに結構いろいろ話題はありました。Coreとしてはこれからも活発に動いていくものと思います。注目していきたいですね。そんな2017年の締めくくり、今年はどんな記事が集まるでしょうか。2017の参加、お待ちしております。2016の15日目です。前回はPowerShellのASTの概要を解説しました。今回は前回の補足というか応用的な内容になります。前回、スクリプトブロックからどのようなASTが生成されるのか、図で書きました。そもそもあの図を作るにあたって、ASTの構造を視覚的に把握したかったので、そのためのスクリプトを書きました。PowerShellで木構造を展開表示する方法は色々ある(※)かと思いますが、今回はJSONとして出力して、表示については他のアプリに任せることにしました。※Format-Customのデフォルトビューは意外と使えるただし、ASTオブジェクトをそのままConvertTo-Jsonコマンドレットに渡すわけにはいきません。いうのも、AST構造を再帰的に展開するには、探索の深さ(-Depth)を大きくしなければいけませんが、そうするとASTではないオブジェクトも逐一展開してしまい、現実的な時間内で終わらなくなってしまいます。そこで、ASTオブジェクトそのものをJSONにするのではなく、必要なプロパティのみ再帰的に取得したカスタムオブジェクトを生成し、それをJSONにする方針を取りました。その成果が以下のコードです。namespace節を使っているので、v5以上必須です。}}本来なら、50種以上あるAstクラスに応じてきちんと場合分けすべきなのですが、コードが長くなるだけなので、動的言語の強みを生かしてダックタイピング的な方法で下位ノードを再帰的に展開しています。Ast>>型であることを確認するのに苦労してますが、多分もっといい方法があると思います...。他はAstオブジェクトそのものか、ReadOnlyCollection<Ast>を返すだけなのでそんなに苦労はないです。Ast抽象クラスに含まれているExtent、Parentプロパティ以外で、Astを要素に含まないプロパティに関しては、ASTの葉として解釈しています。次にこのスクリプトを使って、スクリプトブロックをJSONとして出力します。ast.jsonサンプルとして用いるスクリプトブロックは、前回のものと同じです。これを先ほど書いたGet-Ast関数に渡して、結果をConvertTo-JsonでJSON化しています。この際、探索の深さを100としていますが、ネストが深いスクリプトブロックなどでは、もっと大きくする必要も出てくるかもしれません。Viewerを使って表示してみたのが、以下のスクリーンショットになります。色んなスクリプトのASTを表示して、楽しんでみてください。ASTシリーズはもう少し続きます。Visitorと静的解析のお話です。2016の1日目です。PowerShellアドベントカレンダー、今年も始まりました。みなさまのご協力の甲斐あって、過去5年間はすべて完走していますが、今回もできれば完走を目指していく感じでまいりましょう。色々な立場の方からの視点でPowerShellを俯瞰できるこのイベント、私自身も毎年楽しんでおります。去年も2015年のPowerShellをまとめる的な記事から始めたわけですが、今年も去年に負けず劣らず、大変革の年だったと思いますので、今回も1年を振り返るところからスタートしましょう。去年のPowerShell5.0登場、周辺モジュールのOSS化といった大きな動きがあってから、今年の前半は少しおとなしめ?の界隈でした(5.0のインストーラーにバグがあって一時非公開とか小騒動はありました)が、まず驚いたのがPowerShellそのものではなくて、Windowsで動くbashが登場したというトピックですね。発表があったのは今年の3月末の事です。Linux"という仕組みの上で動作するUbuntu上で動作するbashとして動作させてしまおうというものです。Windows"という名称になります。このbash、Windowsのシステムを管理するためのものではなく、Web等の開発用途を想定して提供されたものです。本来的にはPowerShellとは関係ないのですが、当初は色々と誤解が飛び交ったように思います。曰く、MSはPowerShellを捨ててやっとbashを採用した。PowerShellとは何だったのか。これらの誤解や疑問には、PowerShellの公式ブログで、bashという新たなシェルがWindowsに追加されたが、両者は並立するものだ、PowerShellはこれからも進化するよ!といった異例の公式見解が示されたりもしました。Updateで正式に利用可能となりました。5.1)のプレビュー版が登場しました。10に同梱されたものの、2016正式版までやや時間を要すこととなりました。5.0にはいくつかの機能や改良が加えられ、結局、5.1というバージョンが登場するに至ったものと思われます。Updateという大型アップデート適用で使えるようになりました。2016にも(もちろん)同梱されました。5.1ではローカルユーザーやグループを扱うコマンドレット等が(ようやく?)追加されたりもしています。Server用のPowerShellが、従来のPowerShellと分離した点でしょう。Edition"と呼ばれます。Edition"が新たに登場しました。Core上で動作します。CoreはOSS(オープンソースソフトウェア)となっています。Serverの管理に必要十分な機能を保っているのではないかと個人的には思っています。今年、PowerShell界をもっとも震撼させたニュース、それは間違いなく、今年8月に実施された、PowerShellのオープンソース化でしょう[GitHub]。Editionを含んだ全体だったので驚きました。Macが登場しました。これも一部の方、特にWindowsやMicrosoft製品を普段あまり使われない方に、割と大きなインパクトを与えていたように思います。system!"になったことの意義についてはちょっと語りつくすには時間が足り無さそうですが、敢えて現実ベースの話を先にすると、一般ユーザー(PowerShellをシステム管理に用いている管理者)にとって、すぐに世界が変化するかというとそうではないんじゃないかという気がしています。いうのも、現在のところOSS版のPowerShellのバージョンは「6.0」とされているものの、まだα版の段階で、基本機能はほぼほぼ5.1と変わらないです。OSS版が改良されても、別に今Windowsで使っているPowerShellがすぐに強くなるわけではありません(現在のところ、サイドバイサイドでインストールする)。オープンソース、マルチプラットフォーム展開を始めたといっても、それは現在の所、PowerShell本体とコアモジュールに留まっていて、コマンド数もたかだか数百個程度でしょう(もうちょっとあるかな?)。PowerShellでOS、サーバー、アプリ、インフラを管理するには、専用のコマンドが山ほど必要になってきますが、それらは今まで通り、Windowsの製品にしか含まれないものです。そのような状況で、たとえばLinuxを管理するのには自分でコマンドを作るか、普通にLinuxのコマンドを呼ぶか...あれそれって別に普通のシェルスクリプトでいいんじゃ...とか。Server上のPowerShellに反映され、両者は一本化される、はず、です、たぶん、が、それはまだアナウンスもなく、いつ、どのような形でもたらされるかは不明と云わざるを得ません。この状況はあくまで現時点の状況です。PowerShellで、WindowsもLinuxもMacも一貫したコマンド&スクリプトで管理できる日が来るかもしれませんね。現在のところは、PowerShellの謎挙動に遭遇したとき、ソースを合法的に眺めて思いを馳せることができるようになったのが大きいかと個人的には思います。腕に覚えのある方は、(ルールに従って)どしどしプルリクエストを投げて、PowerShellを自ら育てていただければな、と思います。1.0が登場してちょうど10年ということで、PowerShell10周年イベントがあったりしました。思えば遠くへ来たものですね。PowerShellを取り巻く状況は刻一刻と変化し、去年と今年ではその傾向が顕著です。2016を、どうぞよろしくお願い致します。埋め込み型のプレゼンテーションです。遅くなってすみません。新機能のご紹介」の資料を公開します。札幌は涼しくて、何もかも美味しくて良かったです。夏の関西は人間の生存に適した気候とはとても言えないので、しばらく札幌に滞在していたかったですね。5.1の正式版が利用できるようになるということで、今回、5.0に加えて5.1の新機能もご紹介することにしたためです。(スライドは5.1の新機能の部分以外は、基本的にこれまでの内容と同様です。TP5で試すことができます。2016正式リリースまでの期間がけっこう空いたことと、ラピッドリリースの方針もあって、5.1が短期間で登場することとなりました。Editionに分かれるところだと思います。Serverで動作させることを目的として作られました。Serverの管理はリモート経由でPowerShellを直接的あるいは間接的に用いて行うことになるため、当然ながら必須のコンポーネントとなります。Core上で動作します。Frameworkのサブセットで、マルチプラットフォームで動作し、OSSとして開発されています。Editionとしてこれまで通り利用可能です。5.0、5.1の新機能はMSDNでまとめられているのでそちらもご参照ください。(Preview)追伸。Managementを7月付で再受賞いたしました。おかげで今回のイベントで「関西MVP3人が集結」という触れ込みが嘘にならなくて良かったです。同じ分野でCLR/Hのスタッフでもある素敵なおひげさんも受賞されました。おめでとうございます。|Tweet注:最後に書きましたが、この記事の内容には未解決問題が残っています。はじめに前回は、パイプラインを下流の関数内で打ち切る方法について説明しました。今回は逆に、下流でパイプラインが打ち切られた場合、上流の関数ではどう対応すべきなのか、特にリソース解放処理を焦点にして考察してみます。パイプラインが打ち切られるケース前回も説明しましたが、パイプライン内の関数またはコマンドレットで何らかの例外が発生すると、パイプライン処理がその時点で打ち切られます。パイプライン処理が打ち切られると、後続のprocessブロックのみならず、パイプラインに含まれるすべてのendブロックの実行もスキップされてしまいます。ところでコマンドレットや関数では何かエラーが発生した場合、コマンドレットではWriteErrorメソッド、関数ではWrite-Errorコマンドレットを使ってエラーストリームに、生の例外オブジェクトをラップしたErrorRecordを出力し、呼び出し側のErrorActionの設定にエラー時の処理を委ねるのが基本です。呼び出し時のErrorAction指定がContinue、SilentlyContinue、Ignoreの場合は、パイプラインが中断することはありませんが、StopやInquireで中断した場合は例外(ActionPreferenceStopException)がthrowされ、パイプラインは打ち切られます。-First(StopUpstreamCommandsException)が実行された場合も、同様にパイプラインは打ち切られます。下流のコマンドでパイプラインが打ち切られるケースというのは色々あり得るので、endブロックというのは実行が確約されたものでは全くない、ということに留意しておく必要があります。確実に実行したい後処理というのは色々あると思いますが、特に確保したリソースの解放というのは確実に実行してもらわないと困ります。前述のような背景があるので、何らかのリソースを用いる関数を書く際に、beginブロックでリソースを確保し、processブロックでリソースを利用し、endブロックでリソースを解放する、ということは基本はNGということになります。この点、コマンドレットクラスであれば、IDisposableインターフェースを実装しておけば、コマンドレット終了時にDisposeメソッドをPowerShellが呼んでくれるので、その中にリソース解放処理を記述しておけばOKです。関数ではこの手法が使えないので、代替案を考える必要があります。鷲ノ巣であえとす氏が考案した、beginブロックに後処理用の関数を定義しておく方法では、同じ関数内のprocessブロックで発生したエラーをcatchしてリソース解放処理を走らせることは可能です。残念ながら下流で発生した例外をcatchすることはできず、その場合は後処理がスキップされてしまいます。リソース解放処理を含めた関数あえとす氏の方法を若干アレンジして、下流で例外が発生した場合も確実にリソース解放の後処理を走らせる方法を考えてみました。以下にコードを示します。※クラス構文を使ってますが、これは単に、Disposeできるオブジェクトのサンプルだと思ってください。}}processブロック内のtryブロックでパイプライン下流に値を出力したとき、下流で例外が出てもcatchブロックが実行されないので、代わりに、必ず実行されるfinallyブロックから後処理を呼び出すようにしてみました。パイプライン下流で例外が発生しなかった場合には、processブロック内ではリソース解放処理はしたくないので、例外発生の有無を$processingという変数の値を見ることで確認しています。パイプライン出力したあと下流で例外が出ていれば、$processingの値は$trueのままになるので判断可能です。パイプラインが中断することなく、最後まで実行される場合は、endブロック内でリソース解放処理を行います。$falseの間に例外が発生する可能性のある処理を記述した上で、catchブロックで再throwすれば、併せて対応できるのではないかと思います。2このように、下流でパイプライン打ち切りがあるとendブロックは実行されませんが、リソース解放処理は、きちんとprocessブロック内のfinallyブロックから呼び出されています。end)もちろんパイプラインが最後まで正常に実行された場合も、ちゃんと最後にendブロックでリソース解放が行えるようになっています。endにまたがって機能するusingってどういう構文になるんでしょうね。(14:22追記)と、ここまで書いておいて、この方法では下流で発生した例外には対処できますが、上流で例外が発生した場合はリソース解放が実行されないという問題に気付きました...。すればいいんだ...。|TweetPowerShellのパイプライン処理まず、PowerShellのパイプライン処理について軽くおさらいします。�@begin→�Abegin→�Bbegin→(�@process→�Aprocess→�Bprocess→)×n→�@end→�Aend→�Bendの順に実行されます。(processブロックで「1入力に対し1出力する」場合以外は必ずしもこうならないですが)さて、�Aか�Bのprocessブロック実行中に、何らかの条件を満たした時、パイプラインのprocessの後続処理を打ち切りたい場合はどうすれば良いでしょうか。breakを使った駄目な例ネットでよく見かける以下のようなコード、すなわち「パイプラインはbreakで処理を打ち切ることができる」というのは実は正しくないのです。}}このコードはv2までではそもそも正しく動作しませんが、v3以降では条件によっては正しく動作しているように見えるのが、誤解の元なのかと思います。(というか私も誤解してました。