LoginSignup
7
14

More than 1 year has passed since last update.

PowerShell ワイルドカードと正規表現とエスケープ

Last updated at Posted at 2021-03-11

この記事では以下について説明します。

  1. PowerShellが解釈するシングルクォートダブルクォート、そのエスケープ
  2. コマンド等が解釈するワイルドカードとそのエスケープ
  3. コマンド等が解釈する正規表現とそのエスケープ

2021/07/26 更新:記事を全体的に書き直しました。

PowerShellによる文字列の解釈

PowerShellでは、シングルクォートとダブルクォートのどちらで囲うかによって処理が違います。

参考:about_Quoting_Rules - PowerShell | Microsoft Docs

シングルクォート

シングルクォートで囲った文字列は、そのままの文字列として扱われます。

唯一の例外はシングルクォートで、シングルクォートはシングルクォート自身でエスケープします。

'$i is 5' # Output: $i is 5
'don''t' # Output: don't

ダブルクォート

ダブルクォートで囲った文字列は、変数、式、後述するエスケープシーケンスが置換されます。変数はドル記号 $ を前に付けます。式はドル記号と丸括弧 $( ) 内に記述します。

$i = 5
"$i is 5" # Output: 5 is 5
"${i}th" # Output: 5th
"$(2+3) is 5" # Output: 5 is 5

特殊文字のエスケープ

特殊文字をエスケープするには、バッククォート ` を前に付けます

ダブルクォートはダブルクォート自身でエスケープすることもできます。

$i = 5
"`$i is $i" # Output: $i is 5
"`$(2+3) is $(2+3)" # Output: $(2+3) is 5
"``" # Output: `

"`"" # Output: "
"""" # Output: "

エスケープシーケンス

ダブルクォートで囲った文字列では、以下のエスケープシーケンスなどが使用できます。

シーケンス 説明
`n 改行
`t 水平タブ
`u{x} ユニコード文字(※バージョン5では利用不可)
"Column1`t`tColumn2`t`tColumn3" # Output: Column1         Column2         Column3
"line`nbreak"
<# Output:
line
break
#>

PowerShellで使用できるすべてのエスケープシーケンスとその使い方については、以下の参考リンクをご参照ください。

参考:about_Special_Characters - PowerShell | Microsoft Docs

なお、エスケープシーケンスにならない普通の文字の前にバッククォートを付けた場合は、単にバッククォートが消えます。

"he`llo`,` world`!" # Output: hello, world!

オブジェクトのプロパティの展開

変数(オブジェクト)のプロパティを展開するには、式 $( ) の記法が使えます。

$obj = [PSCustomObject]@{property="hello"}
"property is $($obj.property)" # Output: property is hello

コマンド等による文字列の解釈

一部のコマンドや演算子などでは、ワイルドカードや正規表現がサポートされています。それらの記法を説明します。

ワイルドカード

ワイルドカードは、一部のコマンドおよび -like 演算子でサポートされています。どのコマンドがワイルドカードをサポートしているかは一概に言えませんが、-Path-Name の引数であれば基本的にワイルドカードが使えるようです。

ワイルドカードの説明は以下のとおりです。

ワイルドカード 説明 記述例 一致例
* 0文字以上の任意の文字 a* A, ag, Apple
? 任意の1文字 ?n An, in
[ ] 範囲内の1文字 [a-c] a, b, c
[ ] いずれか1文字 [bcl]ook book, cook, look

参考:

ワイルドカードのエスケープ

ワイルドカードをエスケープするには、バッククォート ` を前に付けます。このとき、バッククォートがPowerShellに解釈されないように、シングルクォートで文字列を囲ったほうがよいです。

'[test] hello' -like '[test]*' # Output: False (※右側の [ ] はワイルドカード扱い)
'[test] hello' -like '`[test`]*' # Output: True

'`test hello' -like '`test*' # Output: False (※右の `t は t に変換されて評価される模様)
'`test hello' -like '``test*' # Output: True

ダブルクォートで文字列を囲うと、最初にPowerShellで解釈されるので、以下のようにバッククォートをエスケープしておく必要が出てきます。

'[test] hello' -like "[test]*" # Output: False
'[test] hello' -like "`[test`]*" # Output: False
'[test] hello' -like "``[test``]*" # Output: True

'`test hello' -like "`test*" # Output: False
'`test hello' -like "``test*" # Output: False
'`test hello' -like "```test*" # Output: False
'`test hello' -like "````test*" # Output: True
'`test hello' -like "`````test*" # Output: False
'`test hello' -like "``````test*" # Output: True

image.png
※下段の ```test は前から順番に `` `t でそれぞれ解釈されます。`t は、-like 演算子にとってはエスケープシーケンスでも何でもないため、単に t になります。

-Path の引数でワイルドカードが必要ない場合は、代わりに -LiteralPath が使えます

Get-ChildItem -Path '[test].txt' # t.txt, e.txt, s.txt がヒット
Get-ChildItem -LiteralPath '[test].txt' # [test].txt がヒット

-Path の引数でエスケープする必要がある場合は、シングルクォートで囲ったとしてもバッククォートが2個 `` 必要となるようです(※Get-ChildItem コマンドで確認。他のコマンドでは不明。おそらく内部的に2回エスケープ処理されているのだと思われます)。

# 名前が[test]から始まるファイルを見つける
Get-ChildItem -Path '[test]*' # NG
Get-ChildItem -Path '`[test`]*' # NG
Get-ChildItem -Path '``[test``]*' # OK

正規表現

正規表現は以下のコマンド、文、演算子で利用できます

  • Select-String
  • switch
  • -match -replace -split 演算子

これらはデフォルトでは大文字と小文字を区別しません。区別する場合は、それぞれ以下のようにします。

  • Select-String -CaseSensitive
  • switch -CaseSensitive
  • -cmatch -creplace -csplit

ここで、正規表現の記法を一部紹介します。他の記法や具体例は、以下の参考リンクをご参照ください。

記号 説明
. 任意の一文字(ワイルドカード)
* 直前の文字の0回以上の繰り返し
+ 直前の文字の1回以上の繰り返し
? 直前の文字が0回か1回
{n} 直前の文字のn回の繰り返し
{n,} 直前の文字のn回以上の繰り返し
{n,m} 直前の文字のn回からm回の繰り返し
^ 文字列の先頭、行頭
$ 文字列の末尾、行末
[a-z] 範囲内の1文字
[abc] いずれか1文字
\w 英数字とアンダースコアの1文字
\d 数字の1文字
\s スペース
\t タブ
\r キャリッジリターン
\n 改行

参考:

正規表現のエスケープ

正規表現内でスケープするにはバックスラッシュ \ を使用します。例えば、ピリオドを表すには \. とします。

-replace 演算子でのキャプチャと置換

<入力> -replace <正規表現>,<置換文字列> では、「正規表現」内の ( ) で囲った部分をキャプチャし、「置換文字列」内で順番に $1 $2 … と記述して変数のように使うことができます(PowerShellの変数ではないことに注意)。

'Japan Tokyo' -replace '(\w+) (\w+)','$2, $1' # Output: Tokyo, Japan

「置換文字列」内でドル記号をエスケープするには $$ とします(※「正規表現」内では \$ でエスケープします)。

'500 USD' -replace '(\d+) USD','$$$1' # Output: $500

ここでも、ダブルクォートで囲うとPowerShellの変数や式などが展開されることに注意します。

$i = 5
'<h> hours' -replace '<h>',"$i" # Output: 5 hours

「置換文字列」内でタブなどの特殊文字を使うにはダブルクォートで囲って `t などを使います(※「正規表現」側では \t などを使います)。

'a,b' -replace ',',"`t" # Output: a       b

あとがき

最近PowerShellの勉強を始めた筆者です。

Get-Alias ? を実行したらよく分からない実行結果が出てきたので、それをきっかけにいろいろ調べた結果、この記事ができました。

以下をご覧ください。

Get-Alias ? # 「1文字のエイリアス」がヒット
Get-Alias '?' # 「1文字のエイリアス」がヒット
Get-Alias '`?' # 「?」がヒット
Get-Alias "?" # 「1文字のエイリアス」がヒット
Get-Alias "`?" # 「1文字のエイリアス」がヒット
Get-Alias "``?" # 「?」がヒット

この記事を最後まで読んでくださった皆さんは、上の実行結果がなぜこのようになるのか、ある程度理解できるようになったことと思います。私もいろいろ調べたおかげで理解できたのでよかったです。

Get-Alias ? の事情について詳しく知りたい場合は、こちらの記事(PowerShell Deep Dive: Understanding Get-Alias, wildcards, escape characters, quoting rules, literal vs. non-literal paths, and the timing of string evaluation – Poshoholic)をご参照ください。

7
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
14