PowerShell、実に気持ち悪い。
Io.FileInfo を使用してみたところ、カレントディレクトリにあるファイルが見つからなかったり、変数に代入出来なくなってしまい、しばらく頭を抱る羽目になったのだが、整理すると以下のような挙動をする事が分かった。
Io.FileInfo を使用してみたところ、カレントディレクトリにあるファイルが見つからなかったり、変数に代入出来なくなってしまい、しばらく頭を抱る羽目になったのだが、整理すると以下のような挙動をする事が分かった。
まず、カレントディレクトリにあるファイルが以下のように見つからない。
どうも、[Io.FileInfo] がカレントディレクトリを解さないらしい。
C:\Users\kou\a にいるのに、C:\Users\kou (これは PowerShell が起動された際の current directory) が初期状態になっている。
cd の結果が反映されてない。
これ、外部クラスだからなの???
カレントディレクトリをプロセスグローバルではなくクラスローカルに持ってるって事???
とりあえず、以下のように Io.Directory::SetCurrentDirectory() に pwd 渡せば解決するけど、これ cd の度にやるんですか?
参考:
PS C:\Users\kou> cd a PS C:\Users\kou\a> dir Directory: C:\Users\kou\a Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2017/01/13 11:11 0 x PS C:\Users\kou\a> $f = [Io.FileInfo] ".\x" PS C:\Users\kou\a> $f Mode LastWriteTime Length Name ---- ------------- ------ ---- darhsl 1601/01/01 9:00 x PS C:\Users\kou\a> $f = [Io.FileInfo] "a\x" PS C:\Users\kou\a> $f Mode LastWriteTime Length Name ---- ------------- ------ ---- -a---- 2017/01/13 11:11 0 x PS C:\Users\kou\a>
どうも、[Io.FileInfo] がカレントディレクトリを解さないらしい。
C:\Users\kou\a にいるのに、C:\Users\kou (これは PowerShell が起動された際の current directory) が初期状態になっている。
cd の結果が反映されてない。
これ、外部クラスだからなの???
カレントディレクトリをプロセスグローバルではなくクラスローカルに持ってるって事???
とりあえず、以下のように Io.Directory::SetCurrentDirectory() に pwd 渡せば解決するけど、これ cd の度にやるんですか?
PS C:\Users\kou> cd a PS C:\Users\kou\a> PS C:\Users\kou\a> ([Io.FileInfo] ".").FullName C:\Users\kou PS C:\Users\kou\a> ([Io.DirectoryInfo] ".").FullName C:\Users\kou PS C:\Users\kou\a> [Io.DirectoryInfo] "." Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2017/01/13 9:33 kou PS C:\Users\kou\a> [Io.Directory]::SetCurrentDirectory((pwd).Path) PS C:\Users\kou\a> ([Io.FileInfo] ".").FullName C:\Users\kou\a PS C:\Users\kou\a> ([Io.DirectoryInfo] ".").FullName C:\Users\kou\a PS C:\Users\kou\a> [Io.DirectoryInfo] "." Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2017/01/13 11:18 a PS C:\Users\kou\a>うわぁ、面倒臭過ぎる。
参考:
- StackOverflow / 2014-08-29: Why does [IO.DirectoryInfo]“.\” not return the current directory?
以下のようにすると変数 $f に "" を代入した際にエラーとなる。
どうやら、[クラス名] って書き方にダブルミーニングがあって、上記の動作から推測するに C++ っぽい書き方をすると以下のような対応になる。
どうもそれは、以下のように書く必要があるらしい。
いや、まぁ C 言語でも
しかし、PowerShell では
更に、$f の初期化の仕方によっては、その後の = オペレーターの挙動が変わってしまっている。
この状態は remove-variable で変数を削除すると解除される。
後者のやり方は $f を [Io.FileInfo] 型に固定していると考えると、単純に $f = "" とするのではなく、自動的に $f = Io.FileInfo("") ってしてくれてるとも考える事が出来で、慣れるとこれは結構便利に使えそうな気はするんだけど、慣れないと凄い気持ち悪い。
あと、1liner 的な書き方する時には結構変な挙動があるみたいで、未定義状態から1回目と2回目で全体の型が異なったりする。
PS C:\Users\kou\a> $f = [Io.FileInfo] "a\x" PS C:\Users\kou\a> $f.GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True FileInfo System.IO.FileSystemInfo PS C:\Users\kou\a> $f = "" PS C:\Users\kou\a> $f.GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True String System.Object PS C:\Users\kou\a> [Io.FileInfo] $f = "a\x" PS C:\Users\kou\a> $f.GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True FileInfo System.IO.FileSystemInfo PS C:\Users\kou\a> $f = "" Cannot convert value "" to type "System.IO.FileInfo". Error: "パスの形式が無効です。" At line:1 char:1 + $f = "" + ~~~~~~~ + CategoryInfo : MetadataError: (:) [], ArgumentTransformationMetadataException + FullyQualifiedErrorId : RuntimeException PS C:\Users\kou\a> remove-variable f PS C:\Users\kou\a> $f = "" PS C:\Users\kou\a>
どうやら、[クラス名] って書き方にダブルミーニングがあって、上記の動作から推測するに C++ っぽい書き方をすると以下のような対応になる。
[Io.FileInfo] $f # new Io.FileInfo($f) って意味 [Io.FileInfo] $f = "a\x" # Io.FileInfo $f("a\x") って意味自分は、後者の書き方で、$f へは String 型 を代入すると共に、全体としては Io.FileInfo 型を返してほしかったのだが、そうは問屋が卸してくれなかった。
どうもそれは、以下のように書く必要があるらしい。
[Io.FileInfo] ($f = "a\x") # new Io.FileInfo($f = "a\x") って意味
いや、まぁ C 言語でも
int *x = 0; // x = 0 の代入 *x = 0; // *x = 0 の代入みたいなダブルミーニングはあるけどさぁ。
しかし、PowerShell では
更に、$f の初期化の仕方によっては、その後の = オペレーターの挙動が変わってしまっている。
$f = [Io.FileInfo] "a\x" # $f へは任意のオブジェクトを代入可能。言うなれば ::operator=()? [Io.FileInfo] $f = "a\x" # $f へは Io.FileInfo のみ代入可能。Io.FileInfo::operator=() もしくは右辺が勝手に Io.FileInfo() で括られる?しかも、これは少なくとも .GetType() メソッドでは区別が付いてない。
この状態は remove-variable で変数を削除すると解除される。
後者のやり方は $f を [Io.FileInfo] 型に固定していると考えると、単純に $f = "" とするのではなく、自動的に $f = Io.FileInfo("") ってしてくれてるとも考える事が出来で、慣れるとこれは結構便利に使えそうな気はするんだけど、慣れないと凄い気持ち悪い。
あと、1liner 的な書き方する時には結構変な挙動があるみたいで、未定義状態から1回目と2回目で全体の型が異なったりする。
PS C:\Users\kou> remove-variable f PS C:\Users\kou> echo ([Io.FileInfo] $f=".") . PS C:\Users\kou> echo ([Io.FileInfo] $f=".") Mode LastWriteTime Length Name ---- ------------- ------ ---- d----- 2017/01/13 9:33 . PS C:\Users\kou> remove-variable f PS C:\Users\kou> ([Io.FileInfo] $f=".").GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True String System.Object PS C:\Users\kou> ([Io.FileInfo] $f=".").GetType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True FileInfo System.IO.FileSystemInfo PS C:\Users\kou> remove-variable f PS C:\Users\kou> [Io.FileInfo] $f="."; $f.getType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True FileInfo System.IO.FileSystemInfo PS C:\Users\kou> [Io.FileInfo] $f="."; $f.getType() IsPublic IsSerial Name BaseType -------- -------- ---- -------- True True FileInfo System.IO.FileSystemInfo PS C:\Users\kou>
タグ
コメントをかく