「ファイル内を検索して対象行のみファイル出力したい。Select-Stringでファイル内を検索することはできるんだけど、ファイル出力すると改行が無視されて全部つながって出力されてしまう。なんとか1行ずつ行単位で出力できないだろうか。」という方向け。
結論、ワイルドカードを使ったLike検索で解決できます。
スポンサーリンク
本記事は下記の4本立てです。
本記事の内容
- 【PowerShell】ファイル内を検索して対象行のみファイル出力したい
- 【PowerShell】ファイル内を検索する方法
- 【PowerShell】ファイル内を検索して対象行のみファイル出力するコーディング
- おまけ:検索キーワードを複数設定して対象行のみ出力する方法(2020/05/16追記)
【PowerShell】ファイル内を検索して対象行のみファイル出力したい
まず、PowerShellで実現したいことを整理しましょう。
今回の記事で想定しているPowerShellで実現したいことは、これ。
指定したフォルダ内には複数ファイルが存在する。
指定したフォルダ内に存在する全てのファイルの中身を検索して、指定したキーワードを含む行だけをテキストファイルに出力したい。
さあ、これをPowerShellで実現するにはどうコーディングすればいいのか。ということです。
【PowerShell】ファイル内を検索する方法
ファイル内を指定した文字列で検索するのに真っ先に思い浮かぶのが『Select-String』というコマンド。
『Select-String』コマンドをかませば瞬時にファイル内の文字列を検索して、ひっかかった行を取得してくれ、出力することも可能なのですが、問題点が…。
それは、検索に引っかかった行が複数存在した場合、改行無視して全て1つの文字列として取得してしまうのです。
『Select-String』を使ってなんとか行単位で取得して出力してくれないものかと試行錯誤するも、すんごい労力がかかりそう…。
ということで、ここは『Select-String』のことなぞきれいさっぱり忘れて、別の方法で実現したほうがいいだろうということで、もう一つの検索方法、Like検索を利用しました。
で、無事解決。
ということで、Like検索を使ったPowerShellのコーディングをご紹介します。
スポンサーリンク
【PowerShell】ファイル内を検索して対象行のみファイル出力するコーディング
プログラムの仕様の補足説明としては下記の通り。
- 検索対象フォルダ:プログラム上であらかじめ指定
- 検索キーワード:入力を促す
- 出力ファイル名:入力を促す(フルパス入力する)
サンプルコードがこちらです。
# 検索対象フォルダを指定
$infolder = "D:\PG"
Write-Host "抽出するキーワードを入力してください。"
$keyword = Read-Host
Write-Host "出力するファイル名を入力してください。"
$outfilename = Read-Host
# 出力するファイルを追記で開く
$outputfile = New-Object System.IO.StreamWriter($outfilename,$true,[Text.Encoding]::GetEncoding("UTF-8"))
# 検索対象フォルダの存在チェック
if (Test-Path $infolder) {
# 検索対象フォルダ内のファイル一覧を取得
$infilelist = Get-ChildItem $infolder
# 1ファイルずつ処理
foreach ($infilename in $infilelist) {
# ファイルの中身取得
$line = Get-Content $infilename.FullName
# 1行ずつ処理
foreach ($getline in $line) {
# キーワードがある行かどうかの判定
if ($getline -like "*$($keyword)*") {
# 出力ファイルに行を書きだす
$outputfile.WriteLine("$($getline)")
}
}
}
}
$outputfile.Close()
コピペで誰でもすぐプログラムの動きを確認することができますよ^^
入力を促す、検索ワードと出力ファイルが詰まっていて見づらいから改行したいという場合には、間に『Write-Host `n』を追記してあげればOKです。
Write-Host "抽出するキーワードを入力してください。"
$keyword = Read-Host
Write-Host `n
※2020/05/16追記
29行目、likeを使わなくても、match演算子を使った下記記述ができますね。
# キーワードがある行かどうかの判定
if ($getline -match $keyword) {
こっちの記述のほうがスマートかな?^^
ファイル処理のプログラムの場合、エラー処理もコーディングしておいたほうが良いです。
上記サンプルコードにエラー処理を追記したコードを【PowerShell】エラー処理(try catch finally)はこう使え!の記事に載せてありますので、そのまままるっとコピペしていただければ使えますよ^^
おまけ:検索キーワードを複数設定して対象行のみ出力する方法
複数ある検索キーワードの中から、いずれかを含むキーワードが行にあった場合に、対象となる行のみ出力したいという場合もあると思います。
その場合、上記サンプルコードをちょこっと改良して、Select-Stringを使えば実現可能。
例えば複数検索キーワードの入力条件を、「30,blue,05」のように「,(カンマ)」で区切る場合、下記コーディングとなります。
# 検索対象フォルダを指定
$infolder = "D:\PG"
Write-Host "抽出するキーワードを入力してください。"
$keyword = Read-Host
# キーワードが入力された場合、カンマで分割してキーワードを取り出す
if ($keyword -ne "") {
$keyword = $keyword.split(',')
}
Write-Host "出力するファイル名を入力してください。"
$outfilename = Read-Host
# 出力するファイルを追記で開く
$outputfile = New-Object System.IO.StreamWriter($outfilename,$true,[Text.Encoding]::GetEncoding("UTF-8"))
# 検索対象フォルダの存在チェック
if (Test-Path $infolder) {
# 検索対象フォルダ内のファイル一覧を取得
$infilelist = Get-ChildItem $infolder
# 1ファイルずつ処理
foreach ($infilename in $infilelist) {
# ファイルの中身取得
$line = Get-Content $infilename.FullName
# キーワードが入力されなかった場合
if ($keyword -eq "") {
foreach ($getline in $line) {
# 出力ファイルに行を書きだす
$outputfile.WriteLine("$($getline)")
}
# キーワードが入力されている場合
} else {
# 1行ずつ処理
foreach ($getline in $line) {
# キーワードがある行かどうかの判定
if ($getline | Select-String -Pattern $keyword) {
# 出力ファイルに行を書きだす
$outputfile.WriteLine("$($getline)")
}
}
}
}
}
$outputfile.Close()
実はこの記述で単一の検索キーワードでの抽出も可能。
ただし、検索キーワードを何も入力せずにリターンキーが押下された場合、エラーとなってしまいますので、その場合の処理を記述する必要があるので、ちとめんどくさいですね。
likeとmatchの場合は県枠キーワードが何も入力されなかった場合はエラーにならずに全行出力されますので、単一キーワード検索のときは、likeかmatchを使ったほうがコーディングは楽かな?と思います。
まとめ
【PowerShell】ファイル内を検索して対象行のみファイル出力する方法について解説しましたがいかがでしたか?
コーディングの見た目、パフォーマンス、特に問題ないと思います。
PowerShellを使った開発の参考になりましたら幸いです。
ではでは~ノシ
スポンサーリンク