目的
今回はPowerShellのファイル操作をまとめてみます。
検証環境
OS |
PSVersion |
Windows10 |
5.1 |
CentOs7 |
7.0.0-preview.3 |
※基本的にWindows10+PowerShell5.1で確認していますが、シンボリックリンク、ハードリンク等の挙動が変わりそうな箇所はCentOS+PowerShell7.0でも確認してます。
やりたい事リスト
カレントディレクトリの取得
従来の方法
Windows10のコマンドプロンプトの例
echo %CD%
CentOs7のシェルの例
pwd
PowerShellの例
PS C:\dev\ps\file> Get-Location
Path
----
C:\dev\ps\file
Get-Locationを使用することで現在作業しているカレントディレクトリを取得できます。
ファイルシステムで実行した場合、返却される値はSystem.Management.Automation.PathInfoになっています。
カレントディレクトリの設定
従来の方法
Windows10のコマンドプロンプトの例
cd c:\dev\ps\file
CentOs7のシェルの例
cd ~/test
PowerShellの例
Set-Locationの例
例1Set-Locationを使用する場合
Set-Location -Literal c:\dev\
Set-Location -Path c:\d?v
Set-Location c:\d?v
Set-Locationを使用してカレントディレクトリを変更可能です。
この際、-Pathまたは-Pathと-LiteralPathを省略をした場合はワイルドカードの指定を受け付けることができます。
もし、これにより複数のパスが帰った場合は以下のエラーが発生します。
> Set-Location -Path c:\d*
Set-Location : パス 'c:\d*' が複数のコンテナーに解決されるため、場所を設定できません。場所を設定できるのは、同時に 1 つ
のコンテナーのみです。
発生場所 行:1 文字:1
+ Set-Location -Path c:\d*
+ ~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Set-Location]、PSArgumentException
+ FullyQualifiedErrorId : Argument,Microsoft.PowerShell.Commands.SetLocationCommand
スタックを利用したカレントディレクトリの設定例
PS C:\dev\ps> Set-Location c:\dev
PS C:\dev> Push-Location -LiteralPath c:\dev\ps
PS C:\dev\ps> Push-Location -Path c:\d?v\ps\file
PS C:\dev\ps\file> Push-Location c:\d?v\ps\right
PS C:\dev\ps\right> Get-Location -Stack
Path
----
C:\dev\ps\file
C:\dev\ps
C:\dev
PS C:\dev\ps\right> Pop-Location
PS C:\dev\ps\file> Pop-Location
PS C:\dev\ps> Pop-Location
PS C:\dev>
Push-Locationはカレントディレクトリをスタックの一番上に積んだのちに、-Path,-Literalで指定したパスをカレントディレクトリとします。
-Pathを指定した場合、ワイルドカードによる指定が可能になりますが、対象が複数になった場合、エラーとなります。
-Path,-LiteralPathを省略してパスを指定した場合、-Pathが指定されたものとしてワイルドカードを受け付けます。
Get-Locationの-Stackオプションを付与することで現在のスタックの状況を表示することが可能です。
Pop-Loacationを使用するとカレントディレクトリは最後にプッシュされた場所に変更します。また、スタックの一番上は削除されます。
スタックを利用することで関数内でカレントディレクトリを変更する処理を行っても呼出し元の処理に影響を与えないようにすることが可能になります。
function test_fun() {
Push-Location c:\dev\
Write-Host "なんかの処理:" (Get-Location).Path
Pop-Location
}
Set-Location c:\
test_fun
Write-Host "カレントディレクトリがc:\であることの確認:" (Get-Location).Path
スタックには名前を付けて積むことも可能です。
C:\> Push-Location -StackName n1 c:\dev
C:\dev> Push-Location -StackName n1 c:\dev\ps
C:\dev\ps> Push-Location -StackName n2 c:\share
C:\share> Get-Location -StackName n1
Path
----
C:\dev
C:\
C:\share> Get-Location -StackName n2
Path
----
C:\dev\ps
C:\share> Pop-Location -StackName n1
C:\dev> Pop-Location -StackName n2
C:\dev\ps> Get-Location -StackName n1
Path
----
C:\
空ファイルの作成
従来の方法
Windows10のコマンドプロンプトの例
echo. 2>test.txt
copy nul test.txt
CentOs7のシェルの例
touch test.txt
PowerShellの例
New-Item ./abc[1].txt -Type File
New-Item -Path ./abc[2].txt -Type File
New-Item . -Name abc[3].txt -Type File
New-Item ./あいうえおおおおお.txt
New-Item -Path ./xxx[1].txt,./xxx[2].txt -Type File
# ワイルドカードを指定して作成
New-Item -Path ./???/ -Name abc1.txt -Type File
New-Item ./???/ -Name abc2.txt -Type File
# 既存のファイルを上書きする
New-Item ./abc[1].txt -Type File -Force
空ファイルを作成する場合はNew-ItemのTypeオプションを省略して実行するか、TypeオプションにFileを指定して実行します。
パスの指定の方法としては-Pathオプションにファイル名までのパスを入れるか、-Pathオプションに親フォルダのパスを指定して、-Nameオプションにファイル名を指定します。
-Pathは省略可能となっており、その場合、一番目のパラメータがPathとみなされます。
-Pathオプションは「,」区切りでパスを指定できます。
-Pathにはワイルドカードを受け付けることが可能です。
また、New-ItemコマンドレットにはLiteralPathが存在しません。
そのため、以下のような挙動を行っているようです。
- -Nameオプションを使用する場合はワイルドカードを受け付ける。
- -Nameオプションを使用しない場合はワイルドカードを受け付けない
新規作成先にすでにファイルが存在する場合、以下のエラーが発生します
New-Item : ファイル 'C:\dev\ps\file\abc[1].txt' は既に存在します。
発生場所 行:1 文字:1
+ New-Item ./abc[1].txt -Type File
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : WriteError: (C:\dev\ps\file\abc[1].txt:String) [New-Item], IOException
+ FullyQualifiedErrorId : NewItemIOError,Microsoft.PowerShell.Commands.NewItemCommand
もし強制的に上書きをする場合は「-Force」オプションを付与します。
フォルダの作成
従来の方法
Windows10のコマンドプロンプトの例
mkdir xyz
CentOs7のシェルの例
mkdir xyz
PowerShellの例
New-Item ./xyz -Type Directory
New-Item -Path ./xyz[2] -Type Directory
New-Item -Path . -Name xyz[3] -Type Directory
New-Item ./xyz1[z],./xyz1[x] -Type Directory
New-Item ./xyz/abc -Type Directory
New-Item ./sonzaisinai/1/2/3/abc -Type Directory
# ワイルドカードの指定
New-Item -Path ./??? -Name yyy -Type Directory
# 存在していてもエラーとしない
New-Item ./xyz -Type Directory -Force
# CentOSでは不可
mkdir -Path xyz[4] -Name xxx
フォルダを作成する場合はNew-ItemのTypeオプションにDirectoryを指定して実行します。
パスに存在しないフォルダが混ざっていても、途中の存在しないフォルダを作成しながらフォルダを作成していきます。
基本的なオプションの使い方は空ファイルの作成で説明したものと同じです。
またWindowsにかぎり、mkdirで同様の処理が行えます。CentOS7ではシェルのmkdirが優先されるため動作しません。
シンボリックリンクの作成
Windowsの場合、シンボリックリンクの作成には管理者権限が必要です。
従来の方法
Windows10のコマンドプロンプトの例
mklink slink_a.txt c:\dev\ps\file\link\a.txt
mklink sdir c:\dev\ps\file\link\sub2 /D
CentOs7のシェルの例
ln ../a.txt ./slink_a.txt -s
ln ../sub2 ./slink_dir -s
PowerShellの例
New-Item -Value '../a.txt' -Path './slink.txt' -ItemType SymbolicLink
New-Item -Value '../sub2' -Path './slink_dir' -ItemType SymbolicLink
# SymbolicLinkの場合LinkTypeはSymbolicLinkとなる
(Get-Item ./slink.txt).LinkType
(Get-Item ./slink_dir).LinkType
# リンク先を表示
(Get-Item ./slink.txt).Target
(Get-Item ./slink_dir).Target
-Valueオプションにリンク先を入力し、-ItemTypeオプションにSymbolicLinkを設定します。
指定のファイルがシンボリックリンクであるか確認するには、Get-Itemを使用してSystem.IO.DirectoryInfoまたはSystem.IO.FileInfoのLinkTypeプロパティとTargetプロパティを確認します。
ジャンクションの作成
従来の方法
Windows10のコマンドプロンプトの例
mklink /j junction_dir c:\dev\ps\file\link\sub1
PowerShellの例
New-Item -Value '../sub1' -Path './junction_dir' -ItemType Junction
# Junctionの場合LinkTypeはJunctionとなる
(Get-Item ./junction_dir).LinkType
# リンク先を表示
(Get-Item ./junction_dir).Target
-Valueオプションにリンク先を入力し、-ItemTypeオプションにJunctionを設定します。
もし-Valueにファイルを指定した場合、下記のエラーが発生します。
New-Item : この操作にはディレクトリが必要です。項目 'C:\dev\ps\file\link\a.txt' はディレクトリではありません。
発生場所 行:1 文字:1
+ New-Item -Value '../a.txt' -Path './junction_txt' -ItemType Junction
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (C:\dev\ps\file\link\a.txt:String) [New-Item]、InvalidOperationException
+ FullyQualifiedErrorId : ItemNotDirectory,Microsoft.PowerShell.Commands.NewItemCommand
CentOS7+PowerShell7で実行した場合、エラーが表示されずにNew-Itemが終了しますが実際にジャンクションは作成されません。
ハードリンクの作成
従来の方法
Windows10のコマンドプロンプトの例
mklink /H hardlink_a.txt c:\dev\ps\file\link\a.txt
CentOs7のシェルの例
ln ../a.txt ./link_a.txt
PowerShellの例
# Windows10 + PowerShell5.1
New-Item -Value '../a.txt' -Path './hard_link_a.txt' -ItemType HardLink
# CentOS7+PowerShell7の場合-Valueにフルパスを入れないとエラーになった
New-Item -Value /home/username/test/link/a.txt -Path './hard_link_a.txt' -ItemType HardLink
# HardLinkの場合LinkTypeはHardLinkとなる
(Get-Item ./hard_link_a.txt).LinkType
# Targetでリンク先のパスを表示する。複数ある場合は複数表示。
# ※CentOS7+PowerShell7だと取得できなかった
(Get-Item ./hard_link_a.txt).Target
-Valueオプションにリンク先を入力し、-ItemTypeオプションにHardLinkを設定します。
もし-Valueにフォルダを指定した場合、下記のエラーが発生します。
New-Item : この操作にはファイルが必要です。項目 'C:\dev\ps\file\link\sub1' はファイルではありません。
発生場所 行:1 文字:1
+ New-Item -Value '../sub1' -Path './hard_link_test.txt' -ItemType Har ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (C:\dev\ps\file\link\sub1:String) [New-Item]、InvalidOperationException
+ FullyQualifiedErrorId : ItemNotFile,Microsoft.PowerShell.Commands.NewItemCommand
ファイルの一覧表示
従来の方法
Windows10のコマンドプロンプトの例
dir c:\dev\
# サブディレクトリを再帰的に表示する例
dir c:\dev\ /s
CentOs7のシェルの例
ls ~/test
# サブディレクトリを再帰的に表示する例
ls ~/test -R
PowerShellの例
単純な例
# カレントディレクトリの一覧
Get-ChildItem
# パスを指定して検索
Get-ChildItem -LiteralPath ./lstestdir
Get-ChildItem -LiteralPath ./lstestdir,./testdir
# ワイルドカードを指定する
Get-ChildItem -Path ./t*,r*
Get-ChildItem ./t*,r*
# サブフォルダを再帰的に呼び出す
Get-ChildItem -LiteralPath ./lstestdir -Recurse
Get-ChildItem -LiteralPath ./lstestdir -r
Get-ChildItemを使用することで指定のパス配下のファイルとディレクトリの一覧を取得できます。
Get-ChildItemはSystem.IO.FileInfoの配列を返します。
結果をそのままコンソールに出力するとWindows10 + PowerShell5.1では以下のような形式で表示されます。
Get-ChildItem -Path C:\Test
Directory: C:\Test
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2/15/2019 08:29 Logs
-a---- 2/13/2019 08:55 26 anotherfile.txt
-a---- 2/12/2019 15:40 118014 Command.txt
-a---- 2/1/2019 08:43 183 CreateTestFile.ps1
-ar--- 2/12/2019 14:31 27 ReadOnlyFile.txt
Modeの意味合いは以下のようになります。
- l (link)
- d (directory)
- a (archive)
- r (read-only)
- h (hidden)
- s (system).
パスを省略して実行した場合はカレントディレクトリの一覧を表示します。
パスの指定は-LiteralPathまたは-Pathを指定して行います。この際、「,」で複数のパスを指定することで一覧表示の対象パスを複数指定することが可能です。
-LiteralPathは-Literalまたは-PsPathと記述することも可能のようです。
-Pathを指定した場合はワイルドカードを受け付けます。
-LiteralPathも-Pathも省略した場合に指定されたパスは-Pathと同様の動作をします。
サブフォルダの内容も取得したい場合は-Recurseを付与します。
デフォルトの検索オプションでは隠しファイルが表示されないことに気をつけてください。
以下のように-Forceオプションを付与することで隠しファイルも表示されるようになります。
Get-ChildItem -Literal ./lstestdir/test -Force
属性を指定した一覧取得
PowerShell3.0以降であれば、ファイルの属性を指定して一覧の取得が可能です。
# 隠しファイルのみ表示する
Get-ChildItem -Hidden
# システムファイルのみ表示する
Get-ChildItem -System
# 読み取り専用のみ表示
Get-ChildItem -ReadOnly
# ディレクトリのみ表示
Get-ChildItem -Directory
# ファイルのみ表示
Get-ChildItem -File
# ファイルでかつ隠しファイルの場合表示
Get-ChildItem -File -Hidden
# 複雑な組み合わせで表示→(読み取り専用 and ディレクトリ以外) or (ディレクトリ以外 and 隠しファイル)
Get-ChildItem -Attributes ReadOnly+!Directory, !Directory+Hidden
-AttributesオプションはFileAttributes Enumを下記の演算子で組み合わせて使用します。
Windows7に初期インストールされているPowerShell2.0ではこれらのオプションは無効なので注意してください。
表示内容を絞りこむ
Get-ChildItemには表示内容を絞り込むオプションがいくつかあります。
# 再帰の深さを制限する
Get-ChildItem -LiteralPath c:\dev\ps\file\testdir -Depth 1
# フィルタを指定して検索
Get-ChildItem -LiteralPath c:\dev\ps\file -Filter *.txt
Get-ChildItem -LiteralPath c:\dev\ps\file -Filter *.txt
Get-ChildItem -LiteralPath c:\dev\ps\file -Filter ????.txt
Get-ChildItem c:\dev\ps\file ????.txt
# Excludeオプションを指定して検索 tで始まるファイルは除く
Get-ChildItem c:\dev\ps\file -Exclude t*
# Excludeオプションを指定して検索 tで始まるファイルと ps1で終わるファイルを除く
Get-ChildItem c:\dev\ps\file -Exclude t*,*.ps1
# Includeオプションを指定して検索 txtで終わる文字
Get-ChildItem c:\dev\ps\file -Recurse -Include *.txt
# aまたはbで始まる文字
Get-ChildItem c:\dev\ps\file -Recurse -Include a*,b*
-depthオプション
-depthオプションは再帰の深さを指定して検索することができます。
たとえば以下のような構造のフォルダが存在するとします。
C:\DEV\PS\FILE\TESTDIR
├─src1
├─src2
└─test
├─a
│ ├─junction_src3
│ ├─junction_src4
│ └─junction_src5
├─b
│ ├─junction_src6
│ └─junction_src7
├─junction_src2
└─symbolic_src1
「-depth 1」で表示対象となるフォルダはsrc1,src2,testまでになります。
「-depth 0」を指定した場合は再帰を行いません。
なお、-depthオプションはPowerShell2.0では使用できません。
-Filterオプション
-Filterオプションは「*」と「!」のワイルドカードを使用してフィルタを行います。
このワイルドカードはいわゆるPowerShellのワイルドカードとは異なります。
では実際に以下のフォルダで-Filterと-Pathで与えられるワイルドカードのふるまいについて検証してみます。
C:\DEV\PS\FILE\LSFILTERTEST
abcd.log
abcd.txt
b.log
b.txt
bbb.log
bbb.txt
c.log
c.txt
cc.log
cc.txt
d.log
d.txt
[bc].log
[bc].txt
実行例
PS C:\dev\ps\file\lsfiltertest> Get-ChildItem -Path ./*.txt
ディレクトリ: C:\dev\ps\file\lsfiltertest
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019/09/06 15:43 0 abcd.txt
-a---- 2019/09/06 15:43 0 b.txt
-a---- 2019/09/06 15:43 0 bbb.txt
-a---- 2019/09/06 15:43 0 c.txt
-a---- 2019/09/06 15:43 0 cc.txt
-a---- 2019/09/06 15:39 0 d.txt
-a---- 2019/09/06 15:43 0 [bc].txt
PS C:\dev\ps\file\lsfiltertest> Get-ChildItem -Literal ./ -Filter *.txt
ディレクトリ: C:\dev\ps\file\lsfiltertest
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019/09/06 15:43 0 abcd.txt
-a---- 2019/09/06 15:43 0 b.txt
-a---- 2019/09/06 15:43 0 bbb.txt
-a---- 2019/09/06 15:43 0 c.txt
-a---- 2019/09/06 15:43 0 cc.txt
-a---- 2019/09/06 15:39 0 d.txt
-a---- 2019/09/06 15:43 0 [bc].txt
PS C:\dev\ps\file\lsfiltertest>
PS C:\dev\ps\file\lsfiltertest> Get-ChildItem -Path ./????.txt
ディレクトリ: C:\dev\ps\file\lsfiltertest
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019/09/06 15:43 0 abcd.txt
-a---- 2019/09/06 15:43 0 [bc].txt
PS C:\dev\ps\file\lsfiltertest> Get-ChildItem -Literal ./ -Filter ????.txt
ディレクトリ: C:\dev\ps\file\lsfiltertest
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019/09/06 15:43 0 abcd.txt
-a---- 2019/09/06 15:43 0 b.txt
-a---- 2019/09/06 15:43 0 bbb.txt
-a---- 2019/09/06 15:43 0 c.txt
-a---- 2019/09/06 15:43 0 cc.txt
-a---- 2019/09/06 15:39 0 d.txt
-a---- 2019/09/06 15:43 0 [bc].txt
PS C:\dev\ps\file\lsfiltertest>
PS C:\dev\ps\file\lsfiltertest> Get-ChildItem -Path ./[bc].txt
ディレクトリ: C:\dev\ps\file\lsfiltertest
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019/09/06 15:43 0 b.txt
-a---- 2019/09/06 15:43 0 c.txt
PS C:\dev\ps\file\lsfiltertest> Get-ChildItem -Literal ./ -Filter [bc].txt
ディレクトリ: C:\dev\ps\file\lsfiltertest
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019/09/06 15:43 0 [bc].txt
この結果から以下のことがわかります。
- *については挙動に差はない
- ?については-Filterについては任意の1文字を表しますが、それは空文字も含みます。この挙動はcmd.exeのdirのワイルドカードと同じ挙動です。
- []については-Filterはサポートしません。
また、-Filterオプションは他のパラメーターよりも効率的に動きます。このことに関する、実際の速度の比較についての情報は以下のブログに記載があります。
Get-ChildItem and the–Include and –Filter parameters
https://tfl09.blogspot.com/2012/02/get-childitem-and-theinclude-and-filter.html
-Excludeオプション
-Excludeオプションで指定した文字のパターンを除外します。
-LiteralPathオプションと組み合わせた場合、期待通り動作しません。
このオプションはワイルドカードを受け付けることが可能です。
「,」区切りで複数のパターンを指定できますが、この場合は指定したパターン全てを除外します。
-Includeオプション
-Pathオプションで指定されたフォルダから特定のアイテムを検索します。
-LiteralPathオプションを使用した場合、期待通り動作しません。
このオプションは-Recurseと共に使用します。
このオプションはワイルドカードを受け付けることが可能です。
「,」区切りで複数のパターンを指定できますが、この場合は指定したパターン全てを受け付けます。
シンボリックリンク、ジャンクションを含む場合
シンボリックリンク、ジャンクションを含むフォルダで下記のコマンドを実行したとします。
Get-ChildItem . -Recurse
この結果は環境によってことなります。
Windows10+Powershell5.1の場合
ディレクトリ: C:\dev\ps\file\link\ps
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----l 2019/09/08 1:44 junction_dir
d----l 2019/09/08 1:59 slink_dir
-a---- 2019/09/08 1:04 12 hard_link_a.txt
-a---l 2019/09/08 1:59 0 slink.txt
ディレクトリ: C:\dev\ps\file\link\ps\junction_dir
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019/09/08 0:54 9 s1.txt
-a---- 2019/09/08 0:54 9 s2.txt
ディレクトリ: C:\dev\ps\file\link\ps\slink_dir
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 2019/09/08 0:55 9 s2_1.txt
-a---- 2019/09/08 0:55 9 s2_2.txt
シンボリックリンク、ジャンクション、ハードリンクについて、Modeに「l」が付与されていることが確認できます。
また、シンボリックリンク、ジャンクションのフォルダを再帰的に探査していきます。
CentOS7+Powershell7の場合
Directory: /home/xxxxxxxx/test/link/ps
Mode LastWriteTime Length Name
---- ------------- ------ ----
l---- 2019/09/08 2:03 slink_dir -> /home/xxxxxxxx/t
est/link/sub2
----- 2019/09/08 0:58 7 hard_link_a.txt
l---- 2019/09/08 1:55 8 slink_a.txt -> /home/xxxxxxxx
/test/link/a.txt
l---- 2019/09/08 2:01 8 slink.txt -> /home/xxxxxxxx/t
est/link/a.txt
シンボリックリンク、ハードリンクについて、Modeに「l」が付与されていることが確認できます。
そして、シンボリックリンクの再帰的な探査は行われません。
もしシンボリックリンク内も探査したい場合は以下のように-FollowSymlinkをつけます。
Get-ChildItem . -Recurse -FollowSymlink
出力書式の変更
パイプを使って書式整形用のコマンドレットに渡すことで様々な書式で表示することが可能です。
Format-Wide
Format-Wideは「dir /w」のような幅広いテーブルで結果を返します。
Get-ChildItem | Format-Wide
ディレクトリ: C:\dev\ps\file\lsfiltertest
abcd.log abcd.txt
b.log b.txt
bbb.log bbb.txt
c.log c.txt
cc.log cc.txt
d.log d.txt
[bc].log [bc].txt
Out-GridView
Out-GridViewは結果をGUIで表示します。
Get-ChildItem | Out-GridView
LinuxやMacなどのWindows以外のプラットフォームにおいて標準では使用できません。
しかし、Microsoft.PowerShell.GraphicalToolsモジュールをインストールすると使用できるようです(未検証)
[PowerShell] 帰ってきたOut-GridView
https://dev.classmethod.jp/server-side/out-gridview-returns-powershell-core/
ファイルの検索
従来の方法
Windows10のコマンドプロンプトの例
where /R c:\dev\ps\file\ *.txt
CentOs7のシェルの例
find ~/test *.txt
PowerShellの例
Get-ChildItem -LiteralPath c:\dev\ps\file\lstestdir -Filter *.txt -Recurse -Force
Get-ChildItem -Path c:\dev\ps\file\lstestdir -Include *.txt -Recurse -Force
# 100バイトより大きいtxtファイルを取得
Get-ChildItem . -Filter *.txt -r | Where-Object { $_.Length -gt 100 }
表示内容を絞りこむで紹介したようにGet-ChildItemの-Filterまたは-Inputオプションを用います。
オプションだけで対応できない場合はWhere-Objectを用いてプロパティを使用して条件を抽出します。
ファイルの削除
従来の方法
Windows10のコマンドプロンプトの例
del test.txt
CentOs7のシェルの例
rm test.txt
PowerShellの例
Remove-Item -LiteralPath test.txt
Remove-Item -LiteralPath test.txt,test2.txt
Remove-Item -Path *.txt
Remove-Item *.txt
# 読み取り専用ファイルを削除する
Remove-Item -LiteralPath readonly.txt -Force
# 何が削除されるか事前に確認する
Remove-Item -Path *.txt -WhatIf
# 削除の確認メッセージを表示する
Remove-Item -Path *.txt -Confirm
# カレントディレクトリのtxt拡張子のファイルをすべて消す
Remove-Item -Path * -Filter *.txt -WhatIf
Remove-Item -Path * -Include *.txt -WhatIf
# カレントディレクトリ以下の全てのフォルダのtxt拡張子ファイルを削除する
Get-ChildItem . -Filter *.txt -Recurse | Remove-Item -WhatIf
ファイルの削除はRemove-Itemで行います。
-Pathオプションを指定した場合、ワイルドカードによる指定が可能になります。
-LiteralPathと-Pathオプションを省略した場合、-Pathと同じ動作をします。
-LiteralPathと-Pathオプションには削除対象のパスをコンマ区切りで複数指定可能です。
読み取り専用のファイルを削除する場合、以下のようなエラーとなります。
この場合は-Forceオプションを付与することで削除がおこなえます。
-WhatIfオプションを付与して実行することで、削除を行わず、削除対象のみを表示します。これはワイルドカードを使用した際に事前に影響を調べるのに有効です。
-Confirmオプションを付与して実行することで各ファイルの削除確認を行いながら削除を進めることが可能になります。
ファイルの一覧表示のGet-ChildItemで出てきた-Filterオプションと-Includeオプションを利用して削除するファイルを絞りこむこともできます。
またGet-ChildItemでファイルを絞り込んだ後にパイプを使ってRemove-Itemに渡すことで削除も可能です。
この際は、予期せぬファイルが消える可能性があるのでWhat-Ifを使用して事前に削除されるファイルを確認したのち削除した方が安全です。
また、Get-ChildItemでファイルを絞る際、シンボリックリンクやジャンクションを使用している場合は、リンク先も削除される可能性があるので慎重に削除しましょう。
フォルダの削除
従来の方法
Windows10のコマンドプロンプトの例
rmdir testdir
rmdir /Q /S lsfiltertest
CentOs7のシェルの例
rmdir testdir
rm -rf y
PowerShellの例
Remove-Item lsfiltertest
Remove-Item lsfiltertest -Recurse
ファイルの削除と同じようにRemove-Itemを使用してファルダを削除します。
削除するフォルダにファイルが存在する場合、下記の確認メッセージが表示されます。
この確認メッセージを出さないで削除するには-Recurseオプションを利用します。
ジャンクション、シンボリックリンクを含むフォルダが存在する場合は、リンク先を破壊する可能性があります。
これらを安全に削除する方法は下記を参考にしてください。
.NETでディレクトリを消すのがこんなに面倒なわけがない
https://needtec.sakura.ne.jp/wod07672/?p=9186
ファイルのコピー
従来の方法
Windows10のコマンドプロンプトの例
copy x.txt xxxx
CentOs7のシェルの例
cp x.txt xxxx
PowerShellの例
Copy-Item -LiteralPath ./x.txt -Destination xxxx
Copy-Item -LiteralPath a.txt,b.txt -Destination xxxx
Copy-Item -LiteralPath ./x.txt -Destination y.txt
Copy-Item -Path x*.txt -Destination xxxx
Copy-Item y*.txt xxxx
# 読み取り専用がコピー先の場合
Copy-Item b.txt readonly.txt -Force
Copy-Item y*.txt xxxx -WhatIf
Copy-Item y*.txt xxxx -Confirm
# カレントディレクトリのすべてのファイルとフォルダのうちtで始まるものをコピーする
Copy-Item * xxxx -Filter t* -WhatIf
# カレントディレクトリのすべてのファイルとフォルダのうちtで始まるもの以外をコピーする
Copy-Item * xxxx -Exclude t* -WhatIf
Copy-Itemを使用してファイルのコピーが可能です。
-LiteralPathまた-Pathオプションにコピー元を指定します。
-Pathオプションを指定した場合、ワイルドカードによる指定が可能になります。
-LiteralPathと-Pathオプションを省略した場合、第一引数をコピー元のパスとして取り扱います。この際、-Pathと同じ動作をします。
-LiteralPathと-Pathオプションにはコピー元のパスをコンマ区切りで複数していできます。
-Destinationにはコピー先のフォルダまたは、コピー先のファイル名を指定します。
コピー先のファイルが読み取り専用の場合はエラーとなります。
この場合、-Forceオプションを付与してコピーします。
-WhatIfオプションを使用することで事前に変更されるパスの確認も可能です。
-Confirmオプションで確認メッセージが表示されます。
ファイルの一覧表示のGet-ChildItemで出てきた-Filter,-Include-Excludeオプションを利用して削除するファイルを絞りこむこともできます。
フォルダのコピー
従来の方法
Windows10のコマンドプロンプトの例
xcopy /e /s /h ./testdir ./xxxx
以下のようになる
xxxx
testdirの子要素1
孫要素
testdirの子要素2
CentOs7のシェルの例
cp ./testdir ./xxxx -R
以下のようになる
xxxx
testdir
testdirの子要素1
孫要素
testdirの子要素2
PowerShellの例
Copy-Item -Literal ./testdir -Destination xxxx -Recurse
ファイルのコピーと同様にCopy-Itemを使用してフォルダのコピーを行います。
コピー先に指定したフォルダの配下にコピー先のディレクトリが作成されます。
この挙動はCentOS7側のフォルダコピー処理と同じです。
ファイル/フォルダの移動
従来の方法
Windows10のコマンドプロンプトの例
# ファイルの移動
move a.txt b.txt
move b.txt folder
# フォルダの移動
move folder folder2
CentOs7のシェルの例
# ファイルの移動
mv a.txt b.txt
mv b.txt folder
# フォルダの移動
mv folder folder2
PowerShellの例
Move-Item -LiteralPath a.txt -Destination b.txt
Move-Item -LiteralPath b.txt -Destination ./folder
Move-Item -LiteralPath ./folder -Destination ./folder2
# ワイルドカードを指定する例
Move-Item -Path a*.txt -Destination ./folder2
Move-Item b*.txt ./folder2
ファイルとフォルダの移動はMove-Itemを用いて行います。
-LiteralPathまたは-Pathには移動元のパスを指定します。
-Pathオプションを指定した場合、ワイルドカードによる指定が可能になります。
-LiteralPathと-Pathオプションを省略した場合、第一引数を移動元のパスとして取り扱います。この際、-Pathと同じ動作をします。
-Destinationオプションには移動先のパスを指定します。-Destinationオプションを省略した場合は第二引数を移動先のパスとします。
-WhatIfオプションを使用することで事前に変更されるパスの確認も可能です。
-Confirmオプションで確認メッセージが表示されます。
ファイル/フォルダの改名
従来の方法
Windows10のコマンドプロンプトの例
ren x.txt xrenamed.txt
CentOs7のシェルの例
mv x.txt xrenamed.txt
PowerShellの例
Rename-Item -Path test.txt -NewName test2.txt
Rename-Item test2.txt test3.txt
# カレントディレクトリの全てのファイルの拡張子をtxt->logに変更
Get-ChildItem *.txt | Rename-Item -NewName { $_.name -Replace '\.txt$','.log' }
ファイルまたはフォルダの改名にはRename-Itemを使用します。
複数のファイルの改名を同時に行う場合はGet-ChildItemでファイルを取得してパイプを用いてRename-Itemに渡します。
-WhatIfオプションを使用することで事前に変更されるパスの確認も可能です。
-Confirmオプションで確認メッセージが表示されます。
ファイルの内容表示
従来の方法
Windows10のコマンドプロンプトの例
type x.txt
CentOs7のシェルの例
cat x.txt
PowerShellの例
Get-Content
Get-Content -Literal ../x.txt
Get-Content -Literal x.txt,y.txt
Get-Content -Path *.txt
Get-Content *.txt
# 最初の10行取得
Get-Content lines.txt -TotalCount 10
# 最後の10行取得
Get-Content lines.txt -Tail 10
# エンコーディングを指定して表示
Get-Content utf8.txt -Encoding Utf8
# バイト配列の取得
Get-Content -Path C:\temp\test.txt -Encoding Byte -Raw
ファイルの内容表示を行うにはGet-Contentを使用します。
-LiteralPath,-Pathオプションには表示対象のファイルパスを指定します。
「,」区切りで複数指定した場合、複数のファイルの内容を表示します。
-Pathオプションを指定した場合、ワイルドカードによる指定が可能になります。
-LiteralPath,-Pathオプションを省略した場合は、指定したパスを-Pathオプションと同じ方法で開きます。
-TotalCountオプションを指定した場合、先頭から指定した行数のみ表示します。
-Tailオプションを指定した場合、末尾から指定した行数のみ表示します。
-TotalCount,-Tailオプションは対象のファイルの改行コードに影響せずに行数を取得してくれるようです。
-Encodingを指定して文字コードを指定したファイルの表示や、バイト配列の取得が可能です。
PowerShell6.0より前は-Encodingはコードページの指定ができず、EUC-JPなどは表示できません。また、UTF8もBOM付きしかサポートしていません。
省略した場合の挙動は「Default」となり、システムの規定のコードページになります。日本語OSの場合はCP932です。
PowerShell5.1+Win10(日本語版) でのEncodingの試験
各種文字コードのファイルがどのEncodingの指定で表示されるかを検証した結果が以下のようになります。
Default |
Unicode |
UTF8 |
EUC-JAのファイル |
× |
× |
× |
SJISのファイル |
〇 |
× |
× |
UNICODEのファイル |
〇 |
〇 |
〇 |
UTF8(BOMなし)のファイル |
× |
× |
〇 |
UTF8(BOMあり)のファイル |
〇 |
〇 |
〇 |
System.IO.Fileを利用する方法
PowerShell5.1以前のGet-Contentはいくつかのエンコーディングしかサポートしていません。
そのため、EUCなどのファイルを読み込む際は.NETのクラスを直接操作する必要があります。
$enc = [System.Text.Encoding]::GetEncoding(20932)
[System.IO.File]::ReadAllLines("c:\dev\ps\file\contenttest\euc.txt", $enc)
ファイルの更新
従来の方法
Windows10のコマンドプロンプトの例
echo xxxx>test.txt
CentOs7のシェルの例
echo xxxx>test.txt
PowerShellの例
Set-Contentを使用する例
Set-Content -LiteralPath .\a.txt -Value 'Hello, World'
Set-Content -LiteralPath a1.txt,a2.txt -Value 'Hello, World'
Set-Content -Path .\b*.txt -Value 'Hello, World'
Set-Content .\c*.txt -Value 'Hello, World'
'Hello, World' | Set-Content -Path .\b*.txt
# UTF8(BOMあり)として更新
Set-Content ./d.txt -Value 'わたしはカモメ' -Encoding Utf8
# バイナリファイルとして更新
Set-Content ./byte.txt -Encoding Byte -Value @([byte]0x30,[byte]0x31,[byte]0x32)
# 事前の確認
Set-Content -Path .\b*.txt -Value 'Hello, World' -WhatIf
Set-Contentを用いることでファイルに更新が行えます。
-Literal,-Pathオプションには更新対象のファイルパスを指定します。
「,」区切りで複数指定した場合、複数のファイルを更新します。
-Pathオプションを指定した場合、ワイルドカードによる指定が可能になります。
ワイルドカードを使用していない場合、指定のファイルが存在しなければ新規にファイルを作成します。
-Valueオプションに書き込む内容を設定します。パイプラインから値を受け付けることもできます。
-Encodingを指定して文字コードを指定したファイルの表示や、バイト配列の取得が可能です。
PowerShell6.0より前は-Encodingはコードページの指定ができず、EUC-JPなどは表示できません。また、UTF8もBOM付きしかサポートしていません。
省略した場合の挙動は「Default」となり、システムの規定のコードページになります。日本語OSの場合はCP932です。
読み取り専用ファイルを書きこんだ場合、規定ではエラーとなります。この場合は-Forceオプションを付与することで上書きが可能になります。
-WhatIfオプションを使用することで事前に更新されるファイルの確認も可能です。
-Filter ,-Include, -Exclude オプションで更新対象のファイルを制御できます。
使用中は Read Lock/Write Lock がかかるので長時間実行されているコマンドのログに使用するのは避けたほうがいいです。
Out-Fileを使用する例
Out-File -LiteralPath .\a.txt -InputObject 'The end of the world'
Out-File -FilePath .\b.txt -InputObject 'The end of the world'
Out-File .\c.txt -InputObject 'The end of the world'
Get-Process | Out-File -FilePath .\Process.txt
Out-File c.txt -InputObject '私はかもめ' -Encoding Utf8
Out-Fileを使用してファイルを更新可能です。
-LiteralPath,-FilePathオプションには更新対象のファイルパスを指定します。
-FilePathにはワイルドカードによる指定が可能ですが、複数更新対象がある場合以下のエラーとなります。
また、ドキュメントにも「Accept wildcard characters: False」とあるので指定できてもやめときましょう。
-InputObjectはファイルに書き込むオブジェクトを指定します。
パイプラインから入力を受け付けることも可能です。
-Encodingを指定して文字コードを指定したファイルの表示や、バイト配列の取得が可能です。
PowerShell6.0より前は-Encodingはコードページの指定ができず、EUC-JPなどは表示できません。また、UTF8もBOM付きしかサポートしていません。
省略した場合の挙動は「UNICODE」となります。
読み取り専用ファイルを書きこんだ場合、規定ではエラーとなります。この場合は-Forceオプションを付与することで上書きが可能になります。
-WhatIfオプションを使用することで事前に更新されるファイルの確認も可能です。
-Confirmオプションを使用することで書き込み前に確認メッセージが表示されます。
Set-ContentとOut-Fileの比較については下記を参考にしてください。
PowerShellの Out-File と Set-Content あるいは Out-File -Append と Add-Content の違い
https://tech.guitarrapc.com/entry/2014/02/11/061627
PowerShell Set-Content and Out-File - what is the difference?
https://stackoverflow.com/questions/10655788/powershell-set-content-and-out-file-what-is-the-difference
System.IO.Fileを利用する方法
PowerShell5.1以前のSet-Content/Out-FileのEncodingはいくつかのエンコーディングしかサポートしていません。
そのため、EUCやUTF8のBOMなしを書き込むさいは.NETのクラスを直接操作する必要があります。
$enc = [System.Text.Encoding]::GetEncoding(20932)
[System.IO.File]::WriteAllLines("c:\dev\ps\file\contenttest\euc_out.txt", "ねこ", $enc)
$enc = New-Object System.Text.UTF8Encoding($False)
[System.IO.File]::WriteAllLines("c:\dev\ps\file\contenttest\utf8_cout.txt", "いぬ", $enc)
ファイルの追記
従来の方法
Windows10のコマンドプロンプトの例
echo xxxx>>test.txt
CentOs7のシェルの例
echo xxx >>test.txt
PowerShellの例
Add-Contentを使用する例
Add-Content -LiteralPath .\a.txt -Value 'end of file'
Add-Content -LiteralPath a1.txt,a2.txt -Value 'end of file'
Add-Content -Path .\b*.txt -Value 'end of file'
Add-Content .\c*.txt -Value 'end of file'
# パイプラインの例。a1の内容をa2に追記
Get-Content a1.txt | Add-Content a2.txt
# UTF8(BOMあり)に追記
Add-Content ./d.txt -Value 'あのこは石ころ' -Encoding Utf8
# バイナリファイルに追記
Add-Content ./byte.txt -Encoding Byte -Value @([byte]0x30,[byte]0x31,[byte]0x32)
Add-Contentを用いることでファイルに更新が行えます。
-LiteralPath,-Pathオプションには更新対象のファイルパスを指定します。
「,」区切りで複数指定した場合、複数のファイルを更新します。
-Pathオプションを指定した場合、ワイルドカードによる指定が可能になります。
ワイルドカードを使用していない場合、指定のファイルが存在しなければ新規にファイルを作成します。
-Valueオプションに書き込む内容を設定します。パイプラインから値を受け付けることもできます。
-Encodingを指定して文字コードを指定したファイルの表示や、バイト配列の取得が可能です。
PowerShell6.0より前は-Encodingはコードページの指定ができず、EUC-JPなどは表示できません。また、UTF8もBOM付きしかサポートしていません。
省略した場合の挙動は「Default」となり、システムの規定のコードページになります。日本語OSの場合はCP932です。
読み取り専用ファイルを書きこんだ場合、規定ではエラーとなります。この場合は-Forceオプションを付与することで上書きが可能になります。
-WhatIfオプションを使用することで事前に更新されるファイルの確認も可能です。
-Filter ,-Include, -Exclude オプションで更新対象のファイルを制御できます。
使用中は Read Lock/Write Lock がかかるので長時間実行されているコマンドのログに使用するのは避けたほうがいいです。
Out-Fileに-Appendオプションを付与して使用する例
Out-File -LiteralPath .\abc.txt -InputObject 'The end of the world' -Append
Out-Fileに-Appendオプションを付与して追記を行います。
それ以外はファイルの更新時にOut-Fileを使用する例と同じです。
System.IO.Fileを利用する方法
PowerShell5.1以前のSet-Content/Out-FileのEncodingはいくつかのエンコーディングしかサポートしていません。
そのため、EUCやUTF8のBOMなしを追記する際は.NETのクラスを直接操作する必要があります。
$enc = [System.Text.Encoding]::GetEncoding(20932)
[System.IO.File]::AppendAllText("c:\dev\ps\file\contenttest\euc_out.txt", "わっふる", $enc)
$enc = New-Object System.Text.UTF8Encoding($False)
[System.IO.File]::AppendAllText("c:\dev\ps\file\contenttest\utf8_cout.txt", "わっしょい", $enc)
ファイルの追記の監視
従来の方法
CentOs7のシェルの例
tail -f log.txt
PowerShellの例
Get-Content -Literal log.txt -Wait
Get-ContentのWaitオプションで類似のことが行えます。
ただし、UNIXのtailコマンドは複数のファイルを受け付けてファイルの更新を監視しますが、Get-Contentの場合、単一のファイルの監視しかできないようです。
ファイルを空にする
従来の方法
Windows10のコマンドプロンプトの例
copy nul test.txt
CentOs7のシェルの例
cp /dev/null test.txt
PowerShellの例
Clear-Content -LiteralPath a.txt
Clear-Content -LiteralPath a1.txt,a2.txt
Clear-Content -Path b*.txt
Clear-Content c*.txt -Force
Get-ChildItem * -File | Clear-Content
ファイルを削除しないが、内容を空にするにはClear-Contentを使用します。
-LiteralPath,-Pathオプションには表示対象のファイルパスを指定します。
「,」区切りで複数指定した場合、複数のファイルの内容を表示します。
-Pathオプションを指定した場合、ワイルドカードによる指定が可能になります。
操作対象のパスはパイプラインの入力から指定も可能です。
読み取り専用ファイルを対象とした場合、規定ではエラーとなります。この場合は-Forceオプションを付与することで上書きが可能になります。
-WhatIfオプションを使用することで事前に更新されるファイルの確認も可能です。
-Confirmオプションを使用することで書き込み前に確認メッセージが表示されます。
-Filter,-Exclude,-Include オプションで対象のフィルタリングが行えます。
ファイルの属性変更
従来の方法
Windows10のコマンドプロンプトの例
attrib y.txt +R
CentOs7のシェルの例
chmod 444 y.txt
PowerShellの例
# 読み取り専用にする
Set-ItemProperty -LiteralPath ./y.txt -Name IsReadOnly -Value $True
# 読み取り専用を解除
Set-ItemProperty -LiteralPath ./y.txt -Name IsReadOnly -Value $False
# 読み取り専用+システムファイル+隠しファイルとする
Set-ItemProperty -LiteralPath ./y.txt -Name Attributes -Value 'Hidden,System,ReadOnly'
# アーカイブ属性を付与
Set-ItemProperty -LiteralPath ./y.txt -Name Attributes -Value 'Archive'
# 全ての属性を外す
Set-ItemProperty -LiteralPath ./y.txt -Name Attributes -Value 'Normal'
# ファイルの作成日,更新日,最終アクセス日を変更する
Set-ItemProperty -LiteralPath ./y.txt -Name CreationTime -Value (Get-Date -Format "yyyy/MM/dd HH:mm
:ss") -Force
Set-ItemProperty -LiteralPath ./y.txt -Name LastWriteTime -Value (Get-Date -Format "yyyy/MM/dd HH:mm
:ss") -Force
Set-ItemProperty -LiteralPath ./y.txt -Name LastAccessTime -Value (Get-Date -Format "yyyy/MM/dd HH:mm
:ss") -Force
# 複数ファイルを対象に操作
Set-ItemProperty -LiteralPath x.txt,y.txt -Name IsReadOnly -Value $True
Set-ItemProperty -Path *.txt -Name IsReadOnly -Value $True -WhatIf
Set-ItemProperty -Path *.txt -Name IsReadOnly -Value $True -Confirm
Set-ItemPropertyを使用してファイルの属性と更新日、作成日、最終更新日を変更可能です。
-LiteralPath,-Pathオプションには表示対象のファイルパスを指定します。
「,」区切りで複数指定した場合、複数のファイルの内容を表示します。
-Pathオプションを指定した場合、ワイルドカードによる指定が可能になります。
操作対象のパスはパイプラインの入力から指定も可能です。
-Nameオプションに与える文字はFileSystemInfo Classのプロパティとなります。
今回使用するものは以下になります。
- Attributes
- Archive、Hidden、 Normal、ReadOnly、または System を設定できます。複数設定数場合はカンマ区切りとします。
- CreationTime
- LastWriteTime
- LastAccessTime
-WhatIfオプションを使用することで事前に更新されるファイルの確認も可能です。
-Confirmオプションを使用することで書き込み前に確認メッセージが表示されます。
-Filter,-Exclude,-Include オプションで対象のフィルタリングが行えます。
ファイルの所有者変更
従来の方法
Windows10のコマンドプロンプトの例
icacls b.txt /setowner NOTE-MAIN\mima
CentOs7のシェルの例
chown test x.txt
PowerShellの例
Hey, Scripting Guy! Windows PowerShell を使用してファイルの所有者を特定する方法はありますかではファイルの所有者を変更するスクリプトを紹介しています。
# 操作対象のファイルのACLを取得して所有者を変更する
$acl = Get-Acl aaa.txt
$user = New-Object System.Security.Principal.NTAccount("NOTE-MAIN", "mima")
$acl.SetOwner($user)
Set-Acl -AclObject $acl -Path aaa.txt
まず所有書を変更したいファイルのアクセス制御リスト(ACL)をGet-Aclで取得します。
Get-Aclで取得できるオブジェクトはSystem.Security.AccessControl.FileSecurityになり、SetOwnerメソッドで所有者を変更します。
SetOwnerメソッドにはNTAccountを与える必要があるのでドメイン名とアカウント名を引数にオブジェクトを作成します。
その後、Set-Aclを使用して所有者を変更したACLオブジェクトを指定のパスに設定します。
Set-AclのLiteralPath、Pathオプションはコンマ区切りで複数のファイルを指定することが可能です。
また、-Pathオプションを指定した場合、ワイルドカードによる指定が可能になります。
ファイル中の文字検索
従来の方法
Windows10のコマンドプロンプトの例
findstr /S a ./*
CentOs7のシェルの例
grep -r a ./*
PowerShellの例
# カレントディレクトリのtxtファイル中にGetが含まれるものを列挙する
Select-String -Path .\*.txt -Pattern 'Get'
# カレントディレクトリ以下すべてののtxtファイル中にGetが含まれるものを列挙する
Get-ChildItem -LiteralPath . -Filter *.txt -Recurse | Select-String -Pattern 'Get'
# unicode/utf8(BOMなし)/utf(BOMあり)のファイルが検索可能
Select-String -Path .\*.txt -Pattern 'あ'
Select-String -Path .\*.txt -Pattern 'あ' -Encoding UTF8
# unicode/utf(BOMあり)のファイルが検索可能
Select-String -Path .\*.txt -Pattern 'あ' -Encoding Unicode
# cp932/unicode/utf(BOMあり)のファイルが検索可能
Select-String -Path .\*.txt -Pattern 'あ' -Encoding Default
# カレントディレクトリのtxtファイルでファイル名に1を含まないものを対象にGetが含まれるものを列挙する
Select-String -Path .\*.txt -Pattern 'Get' -Exclude *1*
# -NotMatchオプションでPatternに一致しない行を列挙する
Select-String -Path *.txt -Pattern "a" -NotMatch
Select-Stringはファイル中の文字列を検索します。
-LiteralPath,-Pathオプションには表示対象のファイルパスを指定します。
「,」区切りで複数指定した場合、複数のファイルの内容を表示します。
-Pathオプションを指定した場合、ワイルドカードによる指定が可能になります。
操作対象のパスはパイプラインの入力から指定も可能です。
-Encodingを指定して文字コードを選択することが可能です。選択したエンコードと実際検索できる内容は[Get-Content時の実験と同じ](#PowerShell5.1+Win10(日本語版) でのEncodingの試験)になります。
PowerShell6.0より前は-Encodingはコードページの指定ができず、EUC-JPなどは表示できません。また、UTF8もBOM付きしかサポートしていません。
省略した場合の挙動はPowerShell5.1では「Utf8」となります。これはオンラインヘルプではDefaultと書いてあるので注意してください。
※実際の挙動とGet-Helpでは「UTF8」です。
-Include,-Excludeオプションでファイルのフィルタリングが行えます
-NotMatchオプションを指定した場合、パターンに一致しない行を列挙します。
出力結果
Select-Stringの出力は規定ではMicrosoft.PowerShell.Commands.MatchInfoのオブジェクトのセットになります。
# 一致した文字のあるファイル名、行番号、行の内容、一致した文字を表示する
Select-String -Path *.txt -Pattern "fa","あ" | % { $_.Filename + " " + $_.LineNumber + " " + $_.Line + " " + $_.Matches }
# euc.txt 2 asdfafaf fa
# sjis.txt 2 asdfafaf fa
# unicode.txt 2 asdfafaf fa
# unicode.txt 3 asfああああ あ
# -Listオプションを付与した場合は、各ファイル1つ見つかったら次行の検査を辞める
Select-String -Path *.txt -Pattern "fa","あ" -List | % { $_.Filename + " " + $_.LineNumber + " " + $_.Line + " " + $_.Matches }
# euc.txt 2 asdfafaf fa
# sjis.txt 2 asdfafaf fa
# unicode.txt 2 asdfafaf fa
Quietパラメーターを使用する場合はSystem.Booleanとなり,見つかったか否かだけを返します。
Select-String -Path *.txt -Pattern "a" -Quiet
# True
>Select-String -Path *.txt -Pattern "ない文字" -Quiet
# False
AllMatchオプション
出力結果に一致したパターンを全て含めるかどうかを制御するオプションです。
諸君 私は戦争が好きだ 諸君 私は戦争が好きだ
諸君 私は戦争が大好きだ 殲滅戦が好きだ
電撃戦が好きだ 打撃戦が好きだ 防衛戦が好きだ 包囲戦が好きだ
突破戦が好きだ 退却戦が好きだ 掃討戦が好きだ 撤退戦が好きだ
# AllMatchオプションを含まない例:
Select-String -LiteralPath sub1/test2.txt -Pattern "諸君","好き" -Encoding Default | % { $_.Filename + " " + $_.LineNumber + " " + $_.Line + " [" + $_.Matches + "]" }
# 出力結果:行あたり一致するパターンを見つけたらその行については検査をやめている。
# test2.txt 1 諸君 私は戦争が好きだ 諸君 私は戦争が好きだ [諸君]
# test2.txt 2 諸君 私は戦争が大好きだ 殲滅戦が好きだ [諸君]
# test2.txt 3 電撃戦が好きだ 打撃戦が好きだ 防衛戦が好きだ 包囲戦が好きだ [好き]
# test2.txt 4 突破戦が好きだ 退却戦が好きだ 掃討戦が好きだ 撤退戦が好きだ [好き]
Select-String -LiteralPath sub1/test2.txt -Pattern "諸君","好き" -Encoding Default -AllMatch | % { $_.Filename + " " + $_.LineNumber + " " + $_.Line + " [" + $_.Matches + "]" }
# 出力結果:行あたり一致するパターンをすべて見つけている。
# test2.txt 1 諸君 私は戦争が好きだ 諸君 私は戦争が好きだ [諸君 諸君]
# test2.txt 2 諸君 私は戦争が大好きだ 殲滅戦が好きだ [諸君]
# test2.txt 3 電撃戦が好きだ 打撃戦が好きだ 防衛戦が好きだ 包囲戦が好きだ [好き 好き 好き 好き]
# test2.txt 4 突破戦が好きだ 退却戦が好きだ 掃討戦が好きだ 撤退戦が好きだ [好き 好き 好き 好き]
Contextオプション
一致したパターンの前後を表示します。
以下の形式で指定して、1番目の数値は一致前の行数、2番目の数値は一致後の行数を表示します。
-Context 2,3
Get-Command | Out-File -FilePath .\Command.txt
Select-String -Path .\Command.txt -Pattern 'Get-Computer' -Context 2, 3
Command.txt:2680:Cmdlet Get-CmsMessage 3.0.0.0 Microsoft.PowerShell.Security
Command.txt:2681:Cmdlet Get-Command 3.0.0.0 Microsoft.PowerShell.Core
> Command.txt:2682:Cmdlet Get-ComputerInfo 3.1.0.0 Microsoft.PowerShell.Management
> Command.txt:2683:Cmdlet Get-ComputerRestorePoint 3.1.0.0 Microsoft.PowerShell.Management
Command.txt:2684:Cmdlet Get-Content 3.1.0.0 Microsoft.PowerShell.Management
Command.txt:2685:Cmdlet Get-ControlPanelItem 3.1.0.0 Microsoft.PowerShell.Management
Command.txt:2686:Cmdlet Get-Counter 3.0.0.0 Microsoft.PowerShell.Diagnostics
Patternオプション
各行で検索するテキストを設定します。
-SimpleMatchオプションを同時に使用した場合は単純な文字列で検索します。
-SimpleMatchオプションを指定しない場合、正規表現となります。
正規表現については以下を参照してください。
また、規定では大文字と小文字は区別されません。
区別を行うには、-CaseSensitiveオプションを付与してください。
実験対象のファイル
aaabb*ccddeeff
bcd
AAABB*CCDDEEFF
BCD
# 正規表現で検索する例
Select-String -LiteralPath test.txt -Pattern "B*C"
# test.txt:1:aaabb*ccddeeff
# test.txt:2:bcd
# test.txt:3:AAABB*CCDDEEFF
# test.txt:4:BCD
# 文字列で検索する例
Select-String -LiteralPath test.txt -Pattern "B*C" -SimpleMatch
# test.txt:1:aaabb*ccddeeff
# test.txt:3:AAABB*CCDDEEFF
# 大文字小文字区別をする例
Select-String -LiteralPath test.txt -Pattern "B*C" -CaseSensitive -SimpleMatch
# test.txt:3:AAABB*CCDDEEFF
フォルダのサイズ取得
PowerShellの例
指定のフォルダ以下のファイルのサイズの合計は以下のようにして取得します。
(Get-ChildItem -LiteralPath . -Recurse -Force | Measure-Object -Sum Length).Sum
ファイルの一覧表示で使用したGet-ChildItemで再帰的にファイルを列挙してMeasure-Objectに渡します。
なお、ジャンクションやシンボリックリンク等を考慮していないので実際のサイズと異なります。
ファイルの存在チェック
PowerShellの例
ni test.txt -Force
Test-Path -LiteralPath test.txt
# True
Test-Path -LiteralPath 存在しない.txt
# False
Test-Path -LiteralPath test.txt,存在しない.txt
# True
# False
# ワイルドカードを使用して特定のフォルダでtxt以外があるか調べる
Test-Path -Path c:\dev\ps\file\grep\* -Exclude *.txt
# 特定の日より新しい
Test-Path -Path t*.txt -NewerThan "2019/09/07 00:00:00" -OlderThan "2019/09/07 10:00:00"
指定したパスが存在するかをTrueまたはFalseで返します。
パスを複数指定した場合、それぞれに対してTrue,Falseを返します。
-Literal,-Pathオプションには対象のファイルパスを指定します。
「,」区切りで複数指定した場合、複数のファイルの内容を検査します。
-Pathオプションを指定した場合、ワイルドカードによる指定が可能になります。
-Filter,-Include,-Excludeを使用してさらに絞り込むこともできます。
よくわからない話
-IsValid
IsValidオプションは実際にファイルパスの有無をチェックせず構文が正しいかチェックするオプションですが、この動きがよくわからん状態になっています。
test-path -isValidの判定が全然isValidじゃない件
https://plaza.rakuten.co.jp/satocchia/diary/201807100000/
PowerShell の Test-Path -IsValid が謎くて使えない
https://tech.guitarrapc.com/entry/2013/09/18/081112
-NewerThanと-OlderThanオプション
-NewerThanと-OlderThanオプションで日付を指定して存在チェックができますが、ワイルドカードを利用した際の挙動が怪しいです。
以下のようなファイルがあるとします。
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 2019/09/07 22:56 sub1
-a---- 2019/09/07 23:47 1613066 Command.txt
-a---- 2019/08/31 12:01 24 euc.txt
-a---- 2019/09/07 11:50 14 euc_out.txt
-a---- 2019/08/31 9:56 26 sjis.txt
-a---- 2019/09/08 0:07 37 test.txt
-a---- 2019/09/07 22:26 8 test1.txt
-a---- 2019/09/07 22:49 10 test2.log
-a---- 2019/09/07 22:49 10 test2.txt
-a---- 2019/08/31 12:01 42 unicode.txt
-a---- 2019/08/31 12:00 28 utf8.txt
-a---- 2019/08/31 12:01 31 utf8BOM.txt
-a---- 2019/09/07 11:50 23 utf8_cout.txt
このフォルダに対して実験をすると以下のようになります。
(Get-Item -LiteralPath test.txt).LastWriteTime
# 2019年9月8日 0:07:02
(Get-Item -LiteralPath test.txt).CreationTime
# 2019年9月8日 0:00:57
Test-Path -Path test.txt -NewerThan "2019/09/08 00:07:00"
# Trueとなる
Test-Path -Path t*.txt -NewerThan "2019/09/08 00:07:00"
# Falseとなる
Test-Path -Path t*.txt -NewerThan "2019/09/08 00:00:58"
# Falseとなる
Test-Path -Path t*.txt -NewerThan "2019/09/08 00:00:57"
# Trueとなる
つまりワイルドカードを指定しない場合は更新日をみて、ワイルドカードを指定した場合は作成日をみている動きをしています。
ヘルプを見る限りこの挙動が意図したものかどうかはわかりませんでした。
パスの結合
PowerShellの例
# 以下のケースはいずれも「c:\dev[1]\work」を作成する
Join-Path c:\dev[1] work
Join-Path -Path c:\dev[1] -ChildPath work
C:\dev\ps\file\grep> Join-Path c:\dev[1]\ \work
# 複数同時に作成も可能
Join-Path c:\dev[1],c:\dev[2] work
# c:\dev[1]\work
# c:\dev[2]\work
# -Resolveで実際あるファイルのみ作成する。この場合、-Pathと-ChildPathはワイルドカードを受け付ける
Join-Path c:\win* system* -Resolve
# C:\Windows\System
# C:\Windows\System32
# C:\Windows\SystemApps
# C:\Windows\SystemResources
# C:\Windows\system.ini
Join-Pathでパスを連結して新しいパスの文字を作成できます。
これによりパスの区切り文字が前後にあるか気にせずパスの作成ができます。
また-Resolveオプションで結合パスの解決を試みます。この際、-Pathと-ChildPathオプションにワイルドカードを指定すると結果が複数になります。
相対パスから絶対パスの変換
PowerShellの例
# 相対パスから絶対パスの変換
Resolve-Path -LiteralPath ../../update
Resolve-Path -Path ../../update
Resolve-Path ../../update
# C:\dev\ps\update
# 絶対パスから相対パスの変換
Resolve-Path -LiteralPath C:\dev\ps\update -Relative
Resolve-Path -Path C:\dev\ps\update -Relative
Resolve-Path C:\dev\ps\update -Relative
# ..\..\update
Resolve-Pathを利用して相対パスから絶対パスの変換ができます。
まとめのまとめ
まとめを作成中に気づいたことや注意した方がいいことを記載しておきます。
- オンラインヘルプは古いか間違っている可能性があるので挙動が怪しかったらGet-Helpで確認する
- 例:PowerShell5.1のSelect-Stringの-Encodingのデフォルト値について
- ワイルドカードを使用する更新処理は想定外のファイルを変更する可能性があるので-WhatIfオプションを使用して事前に確認した方がいい。
- ワイルドカードを使用する必要がない場合はなるべくLiteralPathを利用する
- ファイルシステムで使用できる文字がワイルドカードの文字に含まれているのでエスケープ処理が厄介になる
- シンボリックリンクやジャンクションを含むフォルダの扱いについてはリンク先を変更していいかどうかを考えながら慎重に取り扱う。
- Encodingをサポートしているコマンドレットは可能な限り明示する。
- PowerShell5.1以前は省略した場合の動きがコマンドレット毎に異なる
- PowerShell5.1以前はUTF8はBOMなしであるということに留意する。
- 特に更新系は下手にクロスプラットフォームで使うファイルを更新するとBOMがついて使えなくなる。.NETのファイル操作の関数を呼び出して更新すること
- Aliasは環境ごとに違う。Windowsの場合lsはGet-ItemChildの別名であるが、CentOSでは違う
- 「Get-Alias -Definition Get-ChildItem」というようなコマンドで調査できる。