2012年12月20日木曜日

◆PowerShellのコーディングスタイル

PowerShell Advent Calendar 2012 : ATNDに参加しています。

本来であればPowerShell3.0について書きたいところなのですが、ヘルプの日本語化を待っていたらWindows8がリリースされても一向に提供されず、なんとなく本格的な使用のタイミングを逃してしまいました。

という訳で特に目新しいネタも調べていないので、思いつくままPowerShellの書き方について自分のスタイルを書いていきたいと思います。

C#などの本格的な言語であればコーディングスタイルが議論されることもあるのですがPowerShellではそのような議論をあまり見かけません。
まぁ、ある程度自由で良いのでしょうが一応自分なりに意識している点を、改行の仕方を中心にいくつかあげてみます。

<1行の文字数>

その昔、COBOLやPL/Iなどというホスト用言語を使っていた時は1行72文字とかで決められていたように記憶している。
パンチカードなども使っていたので、そもそもカードの物理的な制約がありましたし、TSS画面なども80文字程度しか表示できなかったように思う。

時代は進み、ハード的な制約はほとんどないのですが読みやすさの観点から言えばやはりある程度に制限するのが妥当でしょう。

私はといえば、やはりだいたい1行80文字から90文字に統一している。
読みやすさもさることながら、ブログなどに書いた場合にスクロールや折り返しが発生しないサイズが目安でしょうか。

<改行>

1行の文字数に大きくかかわってくるのが改行。

ちなみに、.Netでの改行を見ると、C#ではセミコロン「;」が来るまではどこまで行っても論理的に1行。
VBでは物理的な1行が論理的な1行。複数行に跨る場合は継続文字「_」を使う。

PowerShellは見た目的な雰囲気はC#に近いのですが、こと改行になるとVB的な扱いになっている。

PowerShellでは改行に「`」(バッククォート)を使うのですが、こいつは場合によってはディスプレーのゴミと間違う(笑)のであまり使いたくない。

そこで、この改行文字を使わずに1行の文字数を制限するにはどうするかというと、明示的に改行文字を指定しなくてもコーディングが継続する雰囲気を漂わせてあげれば良い。
PowerShellは賢いので雰囲気を察知して継続行として扱ってくれる。
(VBも確かそんな感じですね)

雰囲気というのは以下のようなパターン。

パイプ

001
002
003

dir |
  ?{$_.PSIsContainer}  |
 
 
%{$_.FullName}

括弧{ }

001
002
003

dir | ?{
        
$_.PSIsContainer
       }

括弧( )

001
002

dir | %{if(
 
$_.name -eq "test"){"test found"}}

計算式

001
002
003
004

$x = 10 ; $y = 3
$result =
 
 
$x +
 
 
$y

論理演算子

001
002
003

$x = 10 ; $y = 3
if($x -eq
          10){"10 found"}

ステートメント

001
002
003
004
005
006
007
008
009
010
011

$x = 10 ; $y = 3
if
($x -eq 10){"10 found"
}
 

switch
($x) {
10
 {
   
"10 found"
    break
   }
}

他にも沢山あると思うが、このような感じであえて改行文字を使わずとも改行を行える場所はいくらでもある。
要は、PowerShellが続きがまだあると判断できる場所で改行してやればよいのである。

ただし、一般的に改行に困るケースが1つあって、それはパラメータの数が増えてコマンドレットなどが長くなった場合。

001
002

Get-ChildItem -Path c:\inetpub\logs\* -Include *.log -Exclude hoge.log `
 
-Recurse -Force

残念ながら、このような場合は改行する場所が見当たらない。

そこで、どうしてもという場合は分配演算子というものを使う。
これは、パラメータを連想配列で定義しておき纏めてコマンドレットのパラメータにアサインするというものである。

001
002
003
004
005
006
007
008

$para = @{
  path 
= "c:\inetpub\logs\*"
  Include = "*.log"
  Exclude = "hoge.log"
  Recurse = $true
  Force = $true
}
Get-ChildItem @para

 

1行に纏めてあるものを2行に戻す

ちょっとこれまでの改行とは毛色が違うのだが、もともと複数行のものを「;」で1行に纏めてあるものがある。
これらは「;」をなくして複数行に分割が可能だ。

例えば「集計プロパティ」
(私は慣れるまでおまじないのような記法に見えた)

001
002
003

dir | select @{name="モード";expression={$_.mode}}
dir | select @{name="更新時刻"
               expression={$_.LastWriteTime}} | Out-String

Forループ

001
002
003
004
005
006
007
008
009
010
011
012

for ($index = 0; $index -lt 10; $index++) {
  $index
}
"----"
for
 (
 
$index = 0
  $index -lt 10
  $index++
  ) 
{

  $index
}

 

{ }の書き方

ifステートメントなどで{ } の書き方。
これはPowerShellに限らずC#なども同様で、結構書き方に迷うところである。

私も特に「これ」といった自分のスタイルがあるわけではなくケースバイケースで使い分けているが以下のパターンが比較的多い。

001
002
003
004
005

if($x -eq 1){
 
"1 found"
}else
{
 
"not 1 found"
}

 

エイリアスの使用

エイリアスの使用についても見解の分かれるところかもしれない。
使用頻度の高くないコマンドのエイリアスなどは1見して他人には判り辛いというデメリットがある。

しかし、「dir」などのようにかなり市民権のありそうなエイリアスを「Get-ChildItem」と書くと逆に判り辛いと思う人もいるはずだ。
それ自身が理解できるコマンドである限りにおいては短ければ短いほど直感的に理解し易いものである。

ここら辺は「C#」と「VB」の関係にも似ているように思ったりもする。
当初はVBの方が記述的で判りやすいと思ったりもしたが、慣れてくるとくどい気もしてきて・・・。

少なくとも「Where-Object」「Each-Object」についてはその使用頻度の高さからも「?」「%」で行きたいと個人的には思う。

また、XXXX-Objectコマンドレットは「New-Object」を除けば「XXXX」部分がエイリアスになっていてある程度判りやすいので使っても良い気がしている。
「Sort」や「Group」など・・・・。

関数のネーミング

おそらく、PowerShell的には通常のコマンドレットのようなネーミングを推奨しているものと思う。

しかし、個人的にはコマンドレットとは区別できる名前が好みだ。
特に、V3になってコマンドレットが増えたため見ただけでは区別がつけ辛い。
将来的に名前がバッティングする可能性もあるのでは?と思ったりもしてしまう。

記法を守りつつオレオレ関数と判るような「Get-MyDirectory」なんてのが良いのだろうか?・・・。

 

思いつくままに書いてみましたが、何かしら参考になる部分があれば幸いです。

0 件のコメント:

コメントを投稿