リダイレクト演算子……PowerShellではあまり使ってません。 せいぜい$null破棄時の >$null
でしょうか……
気になるアレがありました。
シェルコマンドの 2>&1 とはどういう意味でしょうか?
Bashは弱い子なので簡潔な説明にへぇっと納得してたのですが……PowerShellでの動作を確認してみましょう。
条件
簡単にエラーを出す方法ということで Get-ChildItem (Alias = dir, ls)で試します。
Get-ChildItemコマンドレットでは、対象ファイルが存在すれば標準出力、対象ファイルが存在しなければ標準エラー出力となります。
Bashに近くなるように、Get-ChildItemは lsと今回は表記しましょう。
今回、D:\にはbcdフォルダを用意しました。 eee.txtはありません。 つまりこの状況です。
この状況下で、bcdでlsしたら標準出力、eee.txtで検索したら標準エラー出力させてリダイレクト演算子の動きを見ます。
テスト1. 標準出力、エラー出力とも出力ファイルを指定
まずは、存在する D:\bcd です。
# 標準出力はD:\test.txtに出力 エラーがd:\test2.txtに0KBで出力。 ls d:\bcd >d:\test.txt 2>D:\test2.txt
次に、存在しない D:\eee.txt で試しましょう。
# 標準出力はD:\test.txtに0KBで出力 エラーがd:\test2.txtに出力。 ls d:\eee.txt >d:\test.txt 2>D:\test2.txt
テスト2. 標準出力に$null指定、エラー出力とも出力ファイルを指定
まずは、存在する D:\bcd です。
# 標準出力が$null破棄。エラーは存在しないので出ない(text2.txtファイルが0KBで生成) ls d:\bcd >$null 2>D:\test2.txt
次に、存在しない D:\eee.txt で試しましょう。
# 標準出力は$null破棄 エラーがd:\test2.txtに出力。 ls d:\eee.txt >$null 2>D:\test2.txt
テスト3. 標準出力にファイルを指定、エラー出力に2>&1を指定
まずは、存在する D:\bcd です。
# 標準出力がd:\test.txtに出力。エラーは存在しないので出ない(ファイルもない) ls d:\bcd >d:\test.txt 2>&1
次に、存在しない D:\eee.txt で試しましょう。
# 標準出力は存在しないので出ない。(ファイルもない) エラーがd:\test.txtに出力。 ls d:\eee.txt >d:\test.txt 2>&1
テスト4. 標準出力に$nullを指定、エラー出力に2>&1を指定
まずは、存在する D:\bcd です。
# 標準出力が$nullに出力。エラーは存在しないので出ない(ファイルもない) ls d:\bcd >$null 2>&1
次に、存在しない D:\eee.txt で試しましょう。
# 標準出力は存在しないので出ない。(ファイルもない) エラーは1にリダイレクト = $nullに破棄 ls d:\eee.txt >$null 2>&1
テスト5. エラー出力に2>&1を指定、標準出力に$nullを指定
テスト4とは、エラー出力と、標準出力の順序を変えています。
まずは、存在する D:\bcd です。
# 標準出力が$nullに出力。エラーは存在しないので出ない(ファイルもない) ls d:\bcd 2>&1 1>$null
次に、存在しない D:\eee.txt で試しましょう。
# 標準出力は存在しないので出ない。(ファイルもない) エラーは1にリダイレクト = $nullに破棄 ls d:\eee.txt 2>&1 1>$null
テスト6. エラー出力に2>&1を指定、標準出力にファイルを指定
テスト4が、&2>と1>のどちらを先に判断しているのか見てみましょう。
まずは、存在する D:\bcd です。
# 標準出力がd:\test.txtに出力。エラーは存在しないので出ない(ファイルもない) ls d:\bcd 2>&1 1>D:\test.txt
次に、存在しない D:\eee.txt で試しましょう。
# 標準出力は存在しないので出ない。(ファイルもない) エラーは、1にリダイレクトされてD:\test.txtに出力 ls d:\eee.txt 2>&1 1>D:\test.txt
まとめ
以上で、リダイレクト演算子の動作がちょっとでもイメージできれば幸いです。
以前指摘していますが、もう一度言います。
| Out-Null
はやめましょう。インアクションでは >$null と同一と記載していますが、比較にならないオーバーヘッドが存在します。
最後に、今回のテストコードを掲載しておきます。 敢えて大袈裟にしてみました (( 本体よりparam()の方が長い
function Get-RedirectOperatorTest{ [CmdletBinding( SupportsShouldProcess = $false, ConfirmImpact = "none", DefaultParameterSetName = "do11" )] param( [Parameter( HelpMessage = "Input path of existing file", Position = 0, Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [ValidateNotNullOrEmpty()] [ValidateScript({Test-Path $_.FullName})] [IO.FileInfo[]] [string]$existFile, [Parameter( HelpMessage = "Input path of not existring file", Position = 0, Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [ValidateNotNullOrEmpty()] [ValidateScript({!(Test-Path $_.FullName)})] [IO.FileInfo[]] [string]$notexistFile, [Parameter( HelpMessage = "Input path of output file for write log success", Position = 0, Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [ValidateNotNullOrEmpty()] [IO.FileInfo[]] [string]$outputSuccess, [Parameter( HelpMessage = "Input path of output file for write log failed", Position = 0, Mandatory = $false, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true )] [ValidateNotNullOrEmpty()] [IO.FileInfo[]] [string]$outputFail, [Parameter(ParameterSetName="do11")] [switch]$do11, [Parameter(ParameterSetName="do12")] [switch]$do12, [Parameter(ParameterSetName="do21")] [switch]$do21, [Parameter(ParameterSetName="do22")] [switch]$do22, [Parameter(ParameterSetName="do31")] [switch]$do31, [Parameter(ParameterSetName="do32")] [switch]$do32, [Parameter(ParameterSetName="do41")] [switch]$do41, [Parameter(ParameterSetName="do42")] [switch]$do42, [Parameter(ParameterSetName="do51")] [switch]$do51, [Parameter(ParameterSetName="do52")] [switch]$do52, [Parameter(ParameterSetName="do61")] [switch]$do61, [Parameter(ParameterSetName="do62")] [switch]$do62 ) switch ($true) { # 標準出力はD:\test.txtに出力 エラーがd:\test2.txtに0KBで出力。 $do11 { "running test 1-1" ls $existFile >$outputSuccess 2>$outputFail } # 標準出力はD:\test.txtに0KBで出力 エラーがd:\test2.txtに出力。 $do12 { "running test 1-2" ls $notexistFile >$outputSuccess 2>$outputFail } # 標準出力が$null破棄。エラーは存在しないので出ない(text2.txtファイルが0KBで生成) $do21 { "running test 2-1" ls $existFile >$null 2>$outputFail } # 標準出力は$null破棄 エラーがd:\test2.txtに出力。 $do22 { "running test 2-1" ls $notexistFile >$null 2>$outputFail } # 標準出力がd:\test.txtに出力。エラーは存在しないので出ない(ファイルもない) $do31 { "running test 3-1" ls $existFile >$outputSuccess 2>&1 } # 標準出力は存在しないので出ない。(ファイルもない) エラーがd:\test.txtに出力。 $do32 { "running test 3-2" ls $notexistFile >$outputSuccess 2>&1 } # 標準出力が$nullに出力。エラーは存在しないので出ない(ファイルもない) $do41 { "running test 4-1" ls $existFile >$null 2>&1 } # 標準出力は存在しないので出ない。(ファイルもない) エラーは1にリダイレクト = $nullに破棄 $do42 { "running test 4-2" ls $notexistFile >$null 2>&1 } # 標準出力が$nullに出力。エラーは存在しないので出ない(ファイルもない) $do51 { "running test 5-1" ls $existFile 2>&1 1>$null } # 標準出力は存在しないので出ない。(ファイルもない) エラーは1にリダイレクト = $nullに破棄 $do52 { "running test 5-2" ls $notexistFile 2>&1 1>$null } # 標準出力がd:\test.txtに出力。エラーは存在しないので出ない(ファイルもない) $do61 { "running test 6-1" ls $existFile 2>&1 1>$outputSuccess } # 標準出力は存在しないので出ない。(ファイルもない) エラーは、1にリダイレクトされてD:\test.txtに出力 $do62 { "running test 6-2" ls $notexistFile 2>&1 1>$outputSuccess } } if (Test-Path (Split-Path $outputSuccess -Parent)) { $openfolder = Split-Path $outputSuccess -Parent Invoke-Item $openfolder } else { $openfolder = $null } }
利用したい時は、そのコードをスイッチ選択し、パスを渡してください。
例: 例1-1のテストを実行するとき
Get-RedirectOperatorTest -existFile d:\bcd -notexistFile d:\eee.txt -outputSuccess D:\test.txt -outputFail D:\test2.txt -do11
DefaultParameterSetName を利用しているので、switchは一つだけ選べるようにしてあります。*1
実行後に -outputSuccessに渡したパスの親フォルダが(存在していれば)開きます。
*1:-do11 を選ぶと -do12などは出なくなる