「 最近は Docker がコンピューターの未来を牽引していくのか、 .NET Core が流行りだよな☆ .NET Framework 離れ☆」
「 .NET Core は Windows から GUI を取り除いたようなやつだが、Visual Studio Code で使えるのも .NET Core だぜ☆
例えば MessageBox のようなダイアログボックスは 基本的に使えない☆
代わりに Read-Host
コマンドなどを使って、昔ながらの文字入力だぜ☆ Yes or No☆?」
「 なんで Power shell は UTF-8 with BOM なの? 頭に3バイト付けてほしくないんだけど?」
「 じゃあ 普段の実践パターンを説明するぜ☆
クラスを使うと他の人が読めなくなるので、グローバル変数なども使うといった、実践的かつ BAD なプログラミングだぜ☆」
「 では、 Power shell ISE を使うのは止めろだぜ☆ Visual studio code を出せだぜ☆」
「 Power shell ISE は Windows に標準搭載されているが、エディターとしては何も助けてくれない☆
二千の00年代までのエディターだぜ☆」
「 それに比べ、 Visual studio code は エクステンションを追加できる☆ 昔でいうプラグインのことだぜ☆
もちろん Power shell も実行できる☆ 前述のとおり .NET Core なんで、 .NET Framework にできて Visual studio code でできないことはある☆」
practice-1.ps1
# Make the directory containing this script current.
Write-Host "Exit | {$(Get-Location)}"
Set-Location $PSScriptRoot
Write-Host "Enter | {$(Get-Location)}"
「 まず最初に、 カレント・ディレクトリ がどこかを はっきりさせろだぜ☆」
「 カレント・ディレクトリ の話しだけで 1記事書けるので、今は飛ばすぜ☆
重要なことは 今どき カレント・ディレクトリ とか 死に機能 でバグの元、使わないで済むなら使いたくないものだぜ☆
しかし残念ながら これから CUI の人気が盛り返したら また復活するかもしらん☆」
「 叩くプログラム
は 同じディレクトリにまとめて置いておく☆
叩くプログラム
の先頭で カレント・ディレクトリ を実行プログラムのある場所にしておく、
必要がなければプログラムの途中で カレント・ディレクトリ は動かさない、
とだけ 覚えておけだぜ☆ なんのことだか 分からんと思うが……☆」
「 Power shell スクリプトのエンコーディングは UTF-8 with BOM に変えておけだぜ☆ 日本語の文字化けを防げる☆
嫌かも知らんが、 Power shell は古いシェルだからな☆」
module-1.ps1
Function Show-MyName() {
Write-Host "むずでょ$(10+29)歳"
}
「 ファイルを複数個に分けたいなんて、すぐに出てくるだろ☆ 最初に教えておいてやろう☆
ちなみに 関数名は好き勝手付けてもいいが、コードチェックを黙らせるような規約は存在する☆」
Approved Verbs for PowerShell Commands
「 英文に触れる機会を多くしておけだぜ☆
しゃべれないかもしれないが、慣れろ☆
お前らは 外国人 と出会うこともないのかもしれないが、出会うことになってから困る☆ メイクセンス☆?」
「 他の言語なら import
文みたいなのがあると思うが Power shell にはない☆ 代わりに ドットソース というのがある☆
これは Power shell ファイルを 上から下まで読むのと おんなじだぜ☆
Power shell は シェルだから、プログラム実行と同じだな☆ だから結局 import
文みたいな使い方ができる☆」
「 Power shell じゃなくて、 Python を使おうぜ☆?」
「 企業勤めをすると ホワイトリスト というのがあってな☆ 使ってもいいプログラムのリストとかなんだが、
Pythonのダウンロードはできるんだが、インストールするときに ポリシー に違反してインストールできないことがある☆
ポリシーというのは 社員のマシンに制限を与えるようなものだぜ☆」
「 プログラマーは 核爆弾ぐらいの危険物ですからね。制限を加えるのは当然よね」
「 ホワイトリスト に Python を入れてくれるように頼めばいいじゃないか☆?」
「 競合会社に利するかもしれない☆
プログラマーは 勤め先によっては シェアの奪い合いに巻き込まれて 制約を受けることがあるんだぜ☆
そんな あなたには Power shell だぜ☆
Windows を使っていて、 Microsoft と競合している勤め先にいることは あんまり ないだろ☆」
「 世界を競合相手に回す会社は コボルや フォートランとか 使ってそうよね」
「 で、どんな感じに Power shell を利用するかなんだが☆」
「 Visual studio code の TERMINAL タブのところが そのまま シェルになっている☆
コマンドを打ち込めば その場で実行できる☆」
Get-Variable
「 例えば Get-Variable コマンドを打鍵すれば、グローバル変数の一覧が出てくる☆
このリストを眺めているだけでも 何ができるか ちょっと分かる☆」
「 ここで注意しておいて欲しいのは、グローバル変数というのは プログラム・ファイル の実行というような区切りでのプロセスではなく、
シェル というプロセスに ずっと残っているということだぜ☆
前の変数が残っているような挙動をし出して 怪しくなったら ゴミ箱アイコンを推して シェルを再起動しろだぜ☆」
「 わたしが よく使う くそプログラム・テクニック はこれだぜ☆」
「 Java Script にも Python にもあるのに……☆」
module-1.ps1
Function Show-MyName() {
Write-Host "むずでょ$(10+29)歳"
}
Function Invoke-Example() {
If ( $global.Options.Apple -cmatch "y") {
Write-Host "Yes, Apple!"
}
If ( $global.Options.Banana -cmatch "y") {
Write-Host "Yes, Banana!"
}
If ( $global.Options.Cherry -cmatch "y") {
Write-Host "Yes, Cherry!"
}
ElseIf ( $global.Options.Cherry -cmatch "n") {
Write-Host "No, Cherry!"
}
If ( $global.Options.Durian -cmatch "y") {
Write-Host "Yes, Durian!"
}
}
Write-Host "He he he!☆(^q^)"
「 別ファイルに Invoke-Example
関数を作ってみよう☆
-cmatch
というのは正規表現のパターンマッチで Case sensitive だぜ☆」
practice-1.ps1
# Make the directory containing this script current.
Write-Host "Exit | $(Get-Location)"
Set-Location $PSScriptRoot
Write-Host "Enter | $(Get-Location)"
# Dot source.
. ".\module-1.ps1"
Show-MyName
# Hashmap, Dictionary.
$global = @{
Options = @{
Apple = "y";
Banana = "n";
Cherry = "iy";
Durian = "";
}
}
Invoke-Example
「 最後に Invoke-Example
コマンドを打つぜ☆ これで実行すると☆」
Exit | C:\Users\むずでょ\OneDrive\ドキュメント\practice-ps1
Enter | C:\Users\むずでょ\OneDrive\ドキュメント\practice-ps1
He he he!☆(^q^)
むずでょ39歳
Yes, Apple!
Yes, Cherry!
「 昔のコンソール画面のメニューに似てるだろ☆ [F1]キーを押してくれだの、[1]キーを押してくれだの☆」
「 プログラムを丸ごとコピー貼り付け という くそBADテクニック で けっこう スピーディーに問題に その場対応 している☆
メンテナンスとか くそくらえ だぜ☆
設定ファイルを用意するとか いろいろ あるかも知れないが、 メイン・スクリプト・ファイル1枚に全部の多値フラグ☆
ひとびとの頭は深く考えることはできない☆ マニュアルも読まない☆ ここに行きつく☆」
「 ここで要点は、最初に実行されるスクリプト・ファイルに ごちゃごちゃ コードを書かないことだぜ☆
書くと 読めなくなる☆ 連想配列だけ 置いておいて、 最後に 関数を呼び出せだぜ☆」
$ErrorActionPreference = "Stop"
「 あと 言うのを忘れていたが、 $ErrorActionPreference
というグローバル変数に Stop
という文字列を入れておけだぜ☆
Power shell はエラーが出ても 次々と コマンドを実行していくが、
$ErrorActionPreference = "Stop"
としておくだけで、エラーがあったときに シェルが止まってくれるぜ☆」
「 頭 痛~☆。 夏休みに風邪でダウンしている☆
パンくずリストは よく使うので この省は書き直そう☆」
practice-4\main.ps1
function Write-Breadcrumb([system.collections.stack]$stack) {
$arr = "$($stack)".Split(" ")
[array]::Reverse( $arr )
$text = $arr -join " > "
Write-Host "Breadcrumb | $($text)"
}
# +
# | Example
# +
$stack = New-Object system.collections.stack
Write-Breadcrumb $stack
$stack.Push("apple")
Write-Breadcrumb $stack
$stack.Push("banana")
Write-Breadcrumb $stack
$stack.Push("cherry")
Write-Breadcrumb $stack
Output
Breadcrumb |
Breadcrumb | apple
Breadcrumb | apple > banana
Breadcrumb | apple > banana > cherry
「 例えば パンくずリストも グローバル変数に1個持っておくといいだろう☆」
$global = @{
Breadcrumb = new-object system.collections.stack;
}
「 本当は パンくずリストは Push のたびに毎回 表示しない方がいい☆ 何かしたときに表示しろだぜ☆」
抜粋
Function Invoke-Example() {
$global.Breadcrumb.Push( $MyInvocation.MyCommand )
Write-Breadcrumb $global.Breadcrumb
$global.Breadcrumb.Push( "Apple" )
Write-Breadcrumb $global.Breadcrumb
If ( $global.Options.Apple -cmatch "y") {
Write-Host "Yes, Apple!"
}
$global.Breadcrumb.Pop() | Out-Null
$global.Breadcrumb.Push( "Banana" )
Write-Breadcrumb $global.Breadcrumb
If ( $global.Options.Banana -cmatch "y") {
Write-Host "Yes, Banana!"
}
$global.Breadcrumb.Pop() | Out-Null
$global.Breadcrumb.Push( "Cherry" )
Write-Breadcrumb $global.Breadcrumb
If ( $global.Options.Cherry -cmatch "y") {
Write-Host "Yes, Cherry!"
}
ElseIf ( $global.Options.Cherry -cmatch "n") {
Write-Host "No, Cherry!"
}
$global.Breadcrumb.Pop() | Out-Null
$global.Breadcrumb.Push( "Durian" )
Write-Breadcrumb $global.Breadcrumb
If ( $global.Options.Durian -cmatch "y") {
Write-Host "Yes, Durian!"
}
$global.Breadcrumb.Pop() | Out-Null
$global.Breadcrumb.Pop() | Out-Null
}
全体の実行結果
Exit | C:\Users\むずでょ\OneDrive\ドキュメント\practice-ps1
Enter | C:\Users\むずでょ\OneDrive\ドキュメント\practice-ps1
He he he!☆(^q^)
むずでょ39歳
Breadcrumb | Invoke-Example
Breadcrumb | Apple Invoke-Example
Yes, Apple!
Breadcrumb | Banana Invoke-Example
Breadcrumb | Cherry Invoke-Example
Yes, Cherry!
Breadcrumb | Durian Invoke-Example
「 使い方の例は むずかしいが、 Push()
と表示、 Pop()
の3つを使っていけだぜ☆
ちなみに Push より Pop の回数が多いと もちろん例外を吐く☆」
「 簡単な パンくずリスト
ができたな☆
スタック・トレースより仕込みに手間がかかるが、エラー経路を探すには手ごろだぜ☆」
「 基本、オプション設定で全部指定するべきなんだが コピー貼り付けのあとの修正を忘れて 大惨事になってしまうことはある☆
ファイルを削除するときに 念押し の手動操作を入れる方法も 説明しておこう☆」
practice-1.ps1 抜粋
if (Show-YesNoDialog "[!] Delete a C:\Uso\dayo.txt") {
Write-Host "(^q^)v"
}
else {
Write-Host "(-_-)"
}
module-1.ps1 抜粋
# +
# | Psuedo dialog.
# +
Function Show-YesNoDialog($message) {
while (1) {
Write-Host $message
$res = Read-Host "(y/n)"
# Ignore case.
switch ($res) {
"y" { return $True }
"n" { return $False }
Default { Start-Sleep -Seconds 1 }
}
}
}
実行結果
[!] Delete a C:\Uso\dayo.txt
(y/n):
[!] Delete a C:\Uso\dayo.txt
(y/n): c
[!] Delete a C:\Uso\dayo.txt
(y/n): Y
(^q^)v
「 No をデフォルトにしたいとかいうときは switch文のところを勝手に改造しろだぜ☆」
「 なんで 今どき 仕様が混ぜくちゃな .ini なのか……☆ というと
プログラムの仕事をくれるのは プログラマーじゃないからだぜ☆
『どこ直せばいいの?』『ここ』 という会話以外をしたら クビになる☆」
INI file parsing in PowerShell
「 コードは Stack overflow に貼り付けてあるコードをもらっていけばいいだろう☆」
ini-parser.ps1
Function Parse-IniFile ($file) {
$ini = @{}
# Create a default section if none exist in the file. Like a java prop file.
$section = "NO_SECTION"
$ini[$section] = @{}
switch -regex -file $file {
"^\[(.+)\]$" {
$section = $matches[1].Trim()
$ini[$section] = @{}
}
"^\s*([^#].+?)\s*=\s*(.*)" {
$name,$value = $matches[1..2]
# skip comments that start with semicolon:
if (!($name.StartsWith(";"))) {
$ini[$section][$name] = $value.Trim()
}
}
}
$ini
}
「 ただし、コードの出所は マイクロソフトのくせに マイクロソフトは コーディング規約に縛られないぜ☆」
Approved Verbs for PowerShell Commands
「 メソッド名は Read-IniFile
ぐらいに変えておくのがいいと思う☆」
config.ini
; +
; | Example.
; |
; | Comment starts with semicolon. Not #.
; | UTF8.
; +
Apple = 1
[Banana]
Cherry = C:\My document\Uso\800.txt
[Date]
Elderberry = The directory has been rebuild.
「 どうでも良かったので 適当に書いた INIファイルだが、
わたしは 単一行コメントは #
より ;
を使うぜ☆
わたしの周りで セミコロンがコメントに使えたプログラムの方が多かったから そうしているだけだが☆」
practice-1.ps1
Set-Location $PSScriptRoot
. "./ini-parser.ps1"
$cnf = Read-IniFile("./config.ini")
Write-Host "Apple | $($cnf["NO_SECTION"]["Apple"])"
Write-Host "Cherry | $($cnf["Banana"]["Cherry"])"
Write-Host "Elderberry | $($cnf["Date"]["Elderberry"])"
Output
Apple | 1
Cherry | C:\My document\Uso\800.txt
Elderberry | The directory has been rebuild.
「 簡単だろ☆ ブーリアン型を扱うには一手間要るが 説明するのが めんどくさいので 気分が向いたときにするぜ☆」
<次の記事>
Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。
また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!
こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?
コメント