[PowerShell] Unixシェルスクリプトとの比較 その2

2020年7月20日月曜日

bash PowerShell

Unixシェルスクリプトとの比較 その1の続き

sed

sedで文字列置換。
$ printf "apple\nbanana\norange\n" | sed "s/an/xyz/g"
apple
bxyzxyza
orxyzge
PS > "apple","banana","orange" | % { $_ -replace "an", "xyz" }
apple
bxyzxyza
orxyzge

-replace演算子も配列に直接適用することができる。
PS > "apple","banana","orange" -replace "an", "xyz"
apple
bxyzxyza
orxyzge

awk


1 2 3 を2乗したものを出力してみる。
bash$ seq 3 | awk 'BEGIN{ print "begin." } {print $1*$1 } END{ print "end." }'
begin.
1
4
9
end.
PS > 1..3 | % -begin{ "begin." } -process{ $_*$_ } -end{ "end." }
begin.
1
4
9
end.

-begin, -process, -end は明示的に書かなくても、{}ブロックを3つ書くと順番に解釈される。
PS > 1..3 | % { "begin." } { $_*$_ } { "end." }
begin.
1
4
9
end.

残念ながら、beginだけ、endだけというのはできないので空のprocessブロックを置く必要がある。
PS > 1..3 | % -end{ "end." }
コマンド パイプライン位置 1 のコマンドレット ForEach-Object
次のパラメーターに値を指定してください:
Process[0]:
end.
PS > 1..3 | % -end{ "end." } {}
end.

% は ForEach-Object のエイリアスなので、以下のように書いても同じ。
PS > 1..3 | foreach-object { "begin." } { $_*$_ } { "end." }
begin.
1
4
9
end.

awkのスクリプトファイルを作るように、フィルタ処理を名前付きのコマンドレットにすることができる。
PS > filter square() {
>>   begin { "begin." }
>>   process { $_*$_ }
>>   end { "end." }
>> }
PS > 1..3 | square
begin.
1
4
9
end.

フィールドの分割
bash$ printf "abc def ghi\n"
abc def ghi
bash$ printf "abc def ghi\n" | awk $'{ print "(\'" $1 "\',\'" $2 "\',\'" $3 "\')" }'
('abc','def','ghi')
PS > "abc def ghi"
abc def ghi
PS > "abc def ghi" | % { $1,$2,$3=$_.Split(" "); "('$1','$2','$3')" }
('abc','def','ghi')

PowerShellでは、%というエイリアスや、filterというキーワードが登場するほど、フィルタが自然な概念になっているのが面白い。