-
Notifications
You must be signed in to change notification settings - Fork 0
MS_PowerShellObjectBasedShell
-
TOP > シェル > PowerShell
- PowerShell オブジェクトベースのシェル
- PowerShell プロバイダとドライブ
- PowerShellのPS1ファイルの作成と実行
-
PowerShell が唯一のオブジェクト・ベースのシェル(perl に似ている)である。
皆、
違いに混乱する。
-
パイプラインで渡せるオブジェクト型がある。
-
パイプラインで何が渡るかは
Get-Memberコマンドレットで調べる
http://mojibake.seesaa.net/article/53585441.html-
シェルだが、プログラム、スクリプト(perl)のような仕様。
-
変数、配列、Property、Method(.NET ライク)、また、
無名関数、delegate、検索条件をラムダ式的に・・・なども可能。
-
# Like This
#
# ↓パイプ ↓ラムダ式的な
get-service | where-object {$_.Status -eq "Running"}
#
# パイプしなくてもキャスト(暗黙)でつなげられる。移行メモ(正誤): 元ページの「Get-Memberコマンドレット調べる」は
「Get-Memberコマンドレットで調べる」の脱字と判断し、補った。
-
Unix / Linux の shell コマンドや、Windows のコマンドプロンプトでも、
「|」を使って、コマンドを複数並べてパイプラインが記述できる。 -
内部的には、標準出力のテキストを次のコマンドの標準入力へ渡している。
-
PowerShell では、PowerShell のオブジェクトをパイプラインで渡すことができる。
- そして、ほとんどの PowerShell コマンドがオブジェクトを出力する。
- また、オブジェクトには、多くのプロパティを含んでいる。
- 後処理のために、オブジェクトにプロパティを追加できる。
- プロパティを判定してフィルタしたり、プロパティを使ってソートできる。
- 最後に
Format-ListやFormat-Tableなどのコマンドを使って、
一部のプロパティを整形して表示できる。
-
.ps1スクリプト内で定義する関数(function)や、自作の Cmdlet でも、
オブジェクトを返すようにしておくと、再利用し易くなる。 -
パイプラインの例は、後述のオブジェクトへメンバー追加の例を参照。
-
パイプラインの詳細は、PowerShell コマンドプロンプトで
get-help about_pipelineを参照。
補足(この違いが実務で効く場面): 「テキストか、オブジェクトか」の差は、
後段の処理の壊れやすさとして現れる。
- テキストベース(
grep/awk/findstr)
出力の書式に依存する。列の位置や区切り文字が変わると壊れる。
ロケールによって日付や桁区切りの表記が変わることも影響する。- オブジェクトベース
プロパティ名に依存する。表示の書式が変わっても影響を受けない。したがって、シェル(スクリプト)の移行で
CMD / WSH から PowerShell へ移す際は、
for /fによるテキスト解析をプロパティ参照に置き換えるのが要点になる。
補足(
Format-*はパイプラインの終端に置く): 初心者が最も引っかかる点として、
Format-Table/Format-Listを通した後のオブジェクトは、
元のオブジェクトではなく整形用のオブジェクトになるという仕様がある。# NG: Format-Table の後で Where-Object しても意図どおり動かない Get-Service | Format-Table | Where-Object { $_.Status -eq "Running" } # OK: 絞り込んでから整形する Get-Service | Where-Object { $_.Status -eq "Running" } | Format-Table本ページが「最後に
Format-ListやFormat-Tableなどのコマンドを使って」
と書いているのは、まさにこの順序を指している。
なお、後続処理でデータとして使うなら
Select-Object/ConvertTo-Json/Export-Csvを使う。
-
PowerShell では、
Add-Memberを使って、
オブジェクトに動的にメンバーを追加できる。 -
OS や他のライブラリが返したオブジェクトに、情報を追加しながら、
パイプラインを使って、順次処理する。といったことができる。
function dirinfo {
param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[object]$dir,
[boolean]$totalup = $false
)
# 空っぽの配列
$dirs = @()
# $dir へ プロパティ追加
$dir | Add-Member -MemberType NoteProperty -Name TotalFiles -Value 0
$dir | Add-Member -MemberType NoteProperty -Name TotalSize -Value 0
foreach ($f in (get-childitem $dir.FullName)) {
if ( $f.Attributes -band [System.IO.FileAttributes]::Directory ) {
# サブフォルダの情報
$ret = dirinfo $f $totalup
if ( $totalup ) {
# 末尾の情報を $dir へ加算
$dir.TotalFiles += $ret[-1].TotalFiles
$dir.TotalSize += $ret[-1].TotalSize
}
$dirs += $ret # サブフォルダ全体を覚える
} else {
$dir.TotalFiles += 1
$dir.TotalSize += $f.Length
$dirs += $f
}
}
$dirs += $dir # $dir自身を末尾に覚える
# 覚えたものをまとめて返す
write-output $dirs
}- 実行例のパイプライン
dirinfo (get-item "c:\program files") | sort-object totalsize -Descending |
where { $_.TotalSize -gt 1 } | select-object -first 5 |
format-list -Property TotalFiles, TotalSize, Fullname(行は折り返して表示しています。実行する際は、1 行に入力してください。)
-
ココでは、以下のことをしている。
-
get-itemでC:\Program Filesフォルダのオブジェクトを取得して、 -
dirinfoでサブフォルダのサイズを集計、 -
sort-objectでTotalSizeの大きい順に並び替えて、 -
whereでTotalSizeが 1 以上のオブジェクトだけ抽出して、 -
select-objectで 最初の 5 個だけ取り出し、 -
format-listで 特定のプロパティのみ表示。
-
移行メモ(正誤): 元ページの
sort-obejctはsort-objectの誤記と判断し、修正した。
補足(
$dirs += $retは要素数が増えると重い): PowerShell の配列は
固定長で、+=のたびに新しい配列を作り直している。
ファイル数が多いフォルダで上記を走らせると、
この行が支配的なコストになる。件数が多い場合は、$dirs = [System.Collections.Generic.List[object]]::new() $dirs.Add($f)のように
List<T>を使うか、パイプラインへ直接流す方が速い。
本ページの参考にある
「大量の出力を扱う場合は、オブジェクト・ベースが仇となる場合もある」
という指摘とも通じる話である。
-
PowerShell:Windowsでおそらく最高のシェル
http://programming-aip.blogspot.jp/2013/01/powershellwindows.html-
最近は、コマンドレットも充実してきて人気も出てきていると思う。
-
分析中で面白いのは、
「大量の出力を扱う場合は、オブジェクト・ベースが仇となる場合もある」
という所である。- 理由は、大量テキスト処理可能な CUI の EXE にパイプさせれば上手く編集できるため。
- しかし、そもそも、Windows の場合、強力なテキスト処理を実装する CUI の EXE が充実していない。
-
補足(この指摘の現在): 著者が挙げる「Windows には強力なテキスト処理の
CUI が充実していない」という状況は、その後変わっている。つまり、現在は「構造化されたデータは PowerShell、
大量のテキストは Unix 系ツール」と使い分けられる。
PowerShell 側もConvertTo-Json/ConvertFrom-Jsonを備えているため、
オブジェクトを JSON にしてjqへ渡すといった連携もしやすい。
-
Windows PowerShell: オブジェクトをカスタマイズするさまざまな方法
http://technet.microsoft.com/ja-jp/magazine/hh750381.aspx -
コンピューターで多くの領域を占有しているフォルダーを確認する方法はありますか
http://gallery.technet.microsoft.com/scriptcenter/4e83afe2-ebdf-414a-bfc9-36e76b7e9750
Tags: シェル, インフラストラクチャ, Windows
このWikiは「Open棟梁Project」,「OSSコンソーシアム 開発基盤部会」によって運営されています。