のえら

技術備忘とかメモとか.間違いはつっこんでいただきたい所存.アフィリエイトはやっていません.

PowerShellのあれやこれ

概要

PowerShellでファイル操作とかする中で、調べたりコマンドヘルプ見たり試したりして溜まった小ネタとかメモとか。パイプとか基本的な部分は書いてない。
ざっくばらんに調べた順になっているのでごちゃごちゃしてる。

小ネタ

入力

タブキー押下で入力補完してくれる。
カーソルがコマンドの間にあるときにタブキーを押下すると、カーソル以降の入力内容は消える。

UNIXコマンドの使用

大体のUNIXコマンドはPowerShellエイリアスがつけられているので使える。
たとえば「cat」「ls」「pwd」とか。

後述の「別名(エイリアス)の取得」も参照。

テキストファイルの行数計測

データベースのレコードから作成したcsvファイルに対して、各何行あるのか調べる。
ぱっと思いついたのはこんな感じ。

Get-Item * -Include *.csv | foreach -process { (Get-Content $_).length }

カレントディレクトリ内のcsvファイルを取得して、foreachでぐるぐるして行数取得してみたけど、一定のファイルサイズになると「'System.OutOfMemoryException' の例外がスローされました。」で落ちる。マジか。

PowerShell使わないでWindowsコマンドでやれば落ちなかったけど、これはこれでなんとなく悔しい。
※1行目はbatで保存したときに、実行したディレクトリに移動するコマンド

cd %~dp0
forfiles /m *.csv /c "cmd /c find /v /c """""" @path"

で、PowerShellで他に行数取得できないかコマンド調査。
計測関数「Measure-Object」コマンドというのがあった。パイプでファイルオブジェクト渡すとLineオプションで行数出力できる。
早速使ってみる。行数だけ欲しいのでFormat-Listでcountのみ出力。

Get-Content hoge.csv | Measure-Object | Format-List count

時間はかかるけどメモリエラーは発生しない。やったね。

他に、System.IO.FileStreamを使用してファイルを読み込み、1行読んだら変数増加、末行まで読んだら変数出力、というやり方がある。省略。

別名で保存

カレントディレクトリ内の特定のファイルに対して何か処理をして、元のファイル名に文字列を付加して保存するやり方。

例1)カレントディレクトリのcsvファイルに対して先頭から2行ずつ取得してそれぞれ別名で保存する(UNIXのhead相当)

Get-Item * -Include *.csv | foreach -Process { gc $_ -TotalCount 2 > $($_.BaseName + "_head_2.csv") }

例2)カレントディレクトリのcsvファイルに対して末尾から10行ずつ取得してそれぞれ別名で保存する(UNIXのtail相当)

Get-Item * -Include *.csv | foreach -Process { gc $_ | Select-Object $_.Path -last 10 > $($_.BaseName + "_last_10.csv") }

拡張子を含まないファイル名の取得はBaseNameプロパティを用いる。
文字列の結合は$()内で行う。これ知らなくて、最初括弧外して記述して、実行時エラーになるわ元のcsvファイル上書きしちゃうわでえらいことになった。。

foreachの話

foreachはForEach-Objectの別名だけど、%も別名なので、上記のコマンドはさらに短く書ける。

Get-Item * -Include *.csv | %{ gc $_ -TotalCount 2 > $($_.BaseName + "_head_2.csv") }

余談で、foreachの改行ってどうするのかと調べてみた。{}をPowerShellが認識するから特殊なコマンド入力とかは不要だよ!って見つけたけど、}を入力した後も「>>」が表示されるからあれ?と思ったら、空入力でエンターキー押せばいいだけだった。。

PS C:\> 30000,56798,12432 | foreach-object -process {
>> $_ / 1024
>> }
>>

↑ここで;とか入れるからだめだった、エンターキー押せば実行される。

.NET Frameworkメソッド呼び出し

たまに「 [System.io.XXX]::HogeHoge」のような記述をみかけるので試してみた。

[System.io.Path]::GetFileNameWithoutExtension("C:\Users\hoge\foobar.txt")

拡張子を除いたファイル名が返却される(この場合「foobar」)

ファイル一覧取得時の小ネタ

ディレクトリ内の一覧表示は ls とか Get-ChildItem とかでできるけど、この一覧をソートしたい場合はパイプで Sort-Object に渡してソート項目を指定する。
以下のコマンドは「最終更新日」でソートする。

Get-ChildItem | Sort-Object lastwritetime -Descending

何も指定しない場合は名前昇順でソートされる。
項目は最終更新日とかサイズとかを指定可能。
降順はDescendingオプションを指定する。

ディレクトリだけ抽出したい場合は PSIsContainer プロパティが使える。

Get-ChildItem -Recurse | ?{ $_.PSIsContainer } | Select-Object fullname

これでもいい。

Get-ChildItem -Recurse | Where-Object { $_.PSIsContainer }

再帰的に全ファイルを抽出するのはこんな感じで書ける。

Get-ChildItem -Recurse | ?{ -not $_.PSIsContainer } | Select-Object fullname
ファイルから文字列検索

ファイルから指定した文字列が含まれる行を検索するには「Select-String」が使える。

Select-String C:\hoge.txt "hoge"

なんだけど、日本語を指定する場合はオプション Encoding に Default を指定する必要がある。

Select-String C:\hoge.txt "ほげ" -Encoding Default
コマンド実行時間の出力

Measure-Command を使用する。

Measure-Command { Get-Content hoge.csv | Measure-Object | Format-List count }

出力結果:

Days : 0
Hours : 0
Minutes : 0
Seconds : 0
Milliseconds : 135
Ticks : 1359836
TotalDays : 1.57388425925926E-06
TotalHours : 3.77732222222222E-05
TotalMinutes : 0.00226639333333333
TotalSeconds : 0.1359836
TotalMilliseconds : 135.9836

フォーマットをHH:MM:SS.msにしたい場合はtoString()が便利。

(Measure-Command { Get-Content hoge.csv | Measure-Object | Format-List count } ).toString()

出力結果:

00:01:33.9708083

プロパティの確認

出力されるオブジェクトと、そのオブジェクトがどんなプロパティを持っているかは Get-Member で調べられる。

Get-ChildItem | Get-Member
別名(エイリアス)の取得

サンプルコードで見かけた「?{}」ってなんじゃろな、と思ったのでPowerShellに聞いてみる。

PS C:\> Get-Alias ?

CommandType     Name                                                Definition
-----------     ----                                                ----------
Alias           %                                                   ForEach-Object
Alias           ?                                                   Where-Object
Alias           h                                                   Get-History
Alias           r                                                   Invoke-History

ForEach-Objectの別名でした、と。
こんな感じで、構文見てなんとなく別名だろうな、と思った場合は「Get-Alias」で聞いてみるといい。「今は『ls』でファイル一覧を表示しているけど、PowerShellのコマンド覚えるかー」と思ったら Get-Alias 使ってコマンド確認する、という状況にも使える(しかしlsのほうが短くて便利である)
※別名の一覧を見たいときは引数なしで呼び出す

が、コマンドについて調べるなら次の「Get-Help」を使ったほうが早かったりする。

何はなくともGet-Help

ヘルプ情報を取得できる Get-Help コマンドが結構できる子。
コマンドのヘルプだけでなく、PowerShellでの別名を調べたり、キーワードから「もしかして」くらいに検索してくれたり、コマンドのサンプルを見たり、意外と有能。

たとえば、ファイル一覧抽出のサンプルを見ていたら「-le」というキーワードがあったけど、コマンドのオプションではなさそう、なんぞこれ?というような状況のときに、ヘルプに聞いてみる。

PS C:\> get-help "-le"

Name Category Synopsis

        • -------- --------

Split-Path Cmdlet 指定されたパス部分を返します。
about_arrays HelpFile データ要素を格納するためのコンパクトなデータ構造について説明します。
about_Break HelpFile Foreach、For、While、Do、または Switch ステートメントを直ちに終了するた...
about_Comparison_Operators HelpFile Windows PowerShell で値を比較する演算子について説明します。
about_For HelpFile 条件テストに基づいてステートメントを実行するのに使用する言語コマンドにつ...
about_operators HelpFile Windows PowerShell でサポートされている演算子について説明します。
about_remote_troubleshooting HelpFile Windows PowerShell でリモート操作のトラブルシューティングを行う方法について
about_scripts HelpFile Windows PowerShellスクリプトを作成および実行する方法について説明します。
about_Special_Characters HelpFile コマンドまたはパラメーター内でその次にある文字を Windows PowerShell がど...

leを含むであろうコマンドやヘルプの一覧が出力されるので、それらしいもの(※)をさらにヘルプで確認する。
(※)ファイル抽出の条件に使っているから演算子かな、というあたりをつける、というのは経験則に基づくのであまりいい例じゃなかった。。

PS C:\> get-help about_operators
トピック
about_Operators
(中略)
比較演算子
比較演算子 (-eq、-ne、-gt、-lt、-le、-ge) は、値を比較して条件をテスト
するときに使用します。たとえば、2 つの文字列値を比較して、それらが等
しいかどうかを判断できます。
(中略)
詳細については、「about_Comparison_Operators」を参照してください。

こんな感じで、ヘルプを追いかけていけばある程度解決できる。

ヘルプのバグ

ヘルプは日本語訳されてる。
が、format-listのヘルプ翻訳で、例2の説明では「これらの」とあるが、2番目のコマンドが記述されていない。
なお、ヘルプの英語版元ページ(https://technet.microsoft.com/ja-jp/library/hh849957.aspx)にはきちんと残っている。
ヘルプに違和感を感じたら英語版読んだほうがいいかも。めったにないと思うけど。

PS C:\> get-help format-list -detailed

名前
Format-List
(中略)
-------------------------- 例 2 --------------------------

C:\PS>$a = get-childitem $pshome\*.ps1xml

説明
-----------
これらのコマンドは、Windows PowerShell ディレクトリの PS1XML ファイルに関する情報を一覧形式で表示します。最初のコマ
ンドは、ファイルを表すオブジェクトを取得し、$a 変数に保存しています。2 番目のコマンドは、Format-List を使用して、$a
に保存されているオブジェクトに関する情報を書式設定しています。このコマンドは、InputObject パラメーターを使用して変
数を Format-List に渡します。変数を受け取った Format-List は書式設定された出力を表示するために既定の出力コマンドレ
ットに送ります。

※抜けているコマンド

PS C:\>format-list -InputObject $a

サイズの大きいcsvファイルから先頭・末尾を取得するときのメモ

csvファイルはサイズが大きく(2GBくらい)なると、ExcelでもテキストエディタでもACCESSでも開けなくなる。
(Windowsコマンドtypeで出力する分には問題ないんだけども)
そんなおっきなcsvファイルの先頭末尾を取得するときのメモ。
windowsコマンドではheadとtailがない。。

headとtailの代替コマンド
MS-DOS バッチファイル Tips - 翔星 Be ランド日記

バッチにして実行してみる

call head.bat *filename* 15 > *tempfilename*

→「このコマンドを実行するのに十分な記憶域がありません。」と出て実行できない。。


メモリが足りなくて実行できないのでPowerShellでやってみる
Windows equivalent of the 'tail' command - Stack Overflow
→この回答を参照してみた(http://stackoverflow.com/a/14341672)

head相当:

powershell -command "& {Get-Content *filename* -TotalCount *n*}"

→TotalCountは先頭から指定された行数取得するオプション
https://technet.microsoft.com/ja-jp/library/hh849787(v=wps.620).aspx

tail相当:

powershell -command "& {Get-Content *filename* | Select-Object -last *n*}"

→コレクション内の末尾から指定の行数を取得する(lastオプション)
 こっちはちょっと時間がかかる
 なお、Ver.3.0からGet-ContentにTailオプションが導入されたのでSelect-Objectを使わなくてもOK

※アンパサンドの意味は?
→引用符で囲まれたスクリプトを実行する場合は、その先頭にアンパサンドが必要

直接PowerShellから実行する場合は括弧内のコマンドだけでよい

おまけ:
PowerShell入門によい記事
https://technet.microsoft.com/ja-jp/scriptcenter/powershell_owner05.aspx

Struts2でアクション内でリクエスト内容を確認する

コントロール内でリクエストされたパラメータをログ出力で確認する方法
パラメータのvalueが配列になっているので、無理くり連結して出力している

for (Entry<String, String[]> ent : request.getParameterMap().entrySet()) {
    log.info(ent.getKey());
    log.info(StringUtils.join(ent.getValue(), ", "));
}

jsPDFをIE8-9に対応させたかった→できませんでした

Blobやatob、ArrayBufferをIE9でも使えるようにして出力を試してみたが、dataURIにIEが対応していないっぽい
jquery - how to get base64 pdf string working in IE ( base64 pdf string is coming from odata call) - Stack Overflow

引用:

According to this you cannot use data uri for navigation in IE.
?Internet Explorer through version 7 (approximately 5% of web traffic as of September 2011), lacks support. However this can be overcome by serving browser specific content.
?Internet Explorer 8 limits data URIs to a maximum length of 32 KB. (Internet Explorer 9 does not have this limitation)
?In IE 8 and 9 data URIs can only be used for images, but not for navigation or Javascript generated file downloads.

そしてIE8ではpolyfillで必死に対応しても無理ゲーだったことをここに記す。

ウォンバットさんたち×ラブライブ!のクロスオーバーが描きたいだけの人生だった(タイトル)

自分の好きな「ウォンバットさんたち」と「ラブライブ!」が一緒になったら幸せなんじゃね?と思った結果の産物。
絵にする気力はなかった。。そのうち。。

【コアラさんとにこにー】
(コアラさん原稿なう)
なに、漫画描いてるの?・・・ふーん、なかなかいい話だけどぉ、そうね、なんだったらにこのアイドル生活密着ドキュメント描いてもいいのよ?
(原稿が進まない・・・)


【コアラさんとにこにー(番外編)】
はいっ にっこにっこにー!
(帰りたい…)


【キウイさんとほのか】
キウイくんってキウイなの?
え、キウイはキウイですが・・・
そっか、キウイくんはキウイなのかー・・・
あっ、キウイは鳥ですよ!?
(ショエー!なんかデジャブ?!)


ウォンバットさんとまきりんぱな】
もぐもぐもぐもぐ…
もぐもぐもぐもぐ…
凛はそんなかよちんも大好きにゃ〜
いみわかんない…


【フェアリーさんとことうみ】
フェアリーはフェアリーなのに飛べないの…
大丈夫、ことりもことりだけど飛べないよ、お揃いだねー
ことりちゃん眩しい・・・!フェアリーもアイドルとして羽ばたきたいなぁ
羽ばたくならば、やはり特訓です!さぁ行きますよ!


【デビルさんとのんたそ(とウォンバットさん)】
やっぱり焼肉はええなぁ♪
俺も肉好きだ!一番の好物はウォンバット
そっかぁ、大好きなんやね〜
(仲良しさんなんやなぁ)

(なんか寒気がするのよぅ…!)


【カモノハシさんとえりちー】
僕は陰湿なんだなぁ
…私も、一人で全部できる、って思っていたこともあったわ、でもね、一緒に歩いてくれる仲間って素敵よ?
(な、なんだかやりづらいんだなぁ…!)