亀の甲羅2

今日もまた朝とく起きて励まなん窓に明るきありあけの月

powershell 正規表現で複数行にわたってパターンマッチさせたい(「単一行モード」)

Ride with GPSでエクスポートしたgpxファイルがGarmin etrex20(英語版)で認識できなかった。

やりたいこと

Ride with GPSでエクスポートしたgpxファイルをGarmin etrex20(英語版)で認識できるgpxファイルに加工したい。

1.問題点

Ride with GPS からエクスポートしたgpxファイルがGarmin etrexで認識されなかったので調査したところ3つの問題点があることが分かった。

  1. "<gpx xmlns~" の行が冗長(何かが悪い)
  2. "<metadata>~</metadata>"が不要
  3. "<name>ほげほげ</name> "の部分が日本語NG(etrex20英語版なので日本語NG。etrex20JならOKなのかな?)

1.1 Ride with GPSでエクスポートされたGPXのサンプル(UTF-8 BOM無し、改行は0x0A"\n")

<?xml version="1.0" encoding="UTF-8"?>
<gpx xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"(・省略・)creator="http://ridewithgps.com/">
  <metadata>
    <name>ほげほげ</name>
    <link href="https://ridewithgps.com/routes/xxxxxx">
      <text>ほげほげ</text>
    </link>
    <time>2023-01-01T00:00:00Z</time>
  </metadata>
  <trk>
    <name>ほげほげ</name>
    <trkseg>
      <trkpt lat="37.00001" lon="140.0001">
        <ele>100.1</ele>
      </trkpt>
(・・・省略・・・)
      <trkpt lat="37.00002" lon="140.0002">
        <ele>100.2</ele>
      </trkpt>
    </trkseg>
  </trk>
</gpx>

1.2 etrex20で実績があるGPXファイル(UTF-8 BOM無し、改行は0x0A"\n")

<?xml version="1.0" encoding="UTF-8"?>
<gpx version="1.1" xmlns="http://www.topografix.com/GPX/1/1">
  <trk>
    <name>hogehoge</name>
    <trkseg>
      <trkpt lat="37.00001" lon="140.0001">
        <ele>100.1</ele>
      </trkpt>
(・・・省略・・・)
      <trkpt lat="37.00002" lon="140.0002">
        <ele>100.2</ele>
      </trkpt>
    </trkseg>
  </trk>
</gpx>

※やるべきこと

  1. "<gpx xmlns~" の行を、下記例に置換
  2. "<metadata>~</metadata>"を削除
  3. "<name>ほげほげ</name> "の部分を英数字に変更(手動)

     

2.これをpowershellでどうにかしよう

2.1.XMLとして読み込むことは諦めた

各要素を楽に扱いたいのでXMLとして読み込んでみようと考えた。よくある以下の方法だと、gpxファイルのLine7あたりでNGがあるって怒られる。

> $XML = [XML](Get-Content C:\Sample1.xml) 

2.2.置換でどうにかしよう

サンプル。

# パス情報:ハードコーディング
$path = "C:\temp\hogehoge.gpx"
$newpath = "C:\temp\hogehoge2.gpx"

# gpxファイル読込
$XML = Get-Content -Encoding UTF8 $path -raw

# 古いファイルは削除
if((Test-Path -LiteralPath $newpath) -eq $true){
    Remove-Item -LiteralPath $newpath
}

# 置換(削除)
# 1.<gpx の行を置換
$XML = $XML -replace "<gpx xmlns:.*>",'<gpx version="1.1" xmlns="http://www.topografix.com/GPX/1/1">'  
# 2.<metadata>~</metadata> を削除(複数行にマッチさせて置換)
$XML = $XML -replace '(?s)\s*<metadata>.+</metadata>',''    

# 出力
$XML | % { [Text.Encoding]::UTF8.GetBytes($_) } | Add-Content -LiteralPath $newpath -Encoding byte

ポイント

  • Get-Content で -raw 指定で読み込むこと
  • -replaceのパターン指定(正規表現)にて、「単一行モード」 を使う。'(?s)pattern' の部分。 「単一行モード」は-rawで読み込まないとだめらしい(どこかのページで見たのだが忘れた。。。orz)
  • out-File -encode UTF8 はBOM付UTF8になってしまうので、「Add-Content」でByte指定で吐き出す。

※「単一行モード」:通常、ピリオド.(任意の文字)には\n(改行)は含まれない(\rは含まれるようだが)。ピリオド.でも改行とマッチさせるようなモードが単一行モードというらしい。

参考

正規表現について - PowerShell | Microsoft Learn
正規表現言語 - クイック リファレンス | Microsoft Learn
正規表現のオプション | Microsoft Learn

バージョン

PSVersion                      5.1.19041.2673  

powershellサンプル ファイルだけ一カ所に集めるスクリプト

ファイル整理の際に

  • 複数のフォルダに分かれている(数が多い)
  • フォルダが深すぎる、多分岐すぎる

みたいなことがあると、非常に面倒。
「とりあえず全部1つのフォルダにまとめちゃえ!」方式のスクリプト例。

# 適宜変更のこと。外部からCALLするようなことは考えていないので直コーディング
$fromPath = "C:\xxx\fromfolder"
$toPath = "C:\xxx\tofolder"

$a = Get-ChildItem -LiteralPath $fromPath -Recurse -File

$a | %{
    # ユニークファイル名とするため、日時(ミリ秒)を取得
    $prefix = Get-Date -Format yyyyMMddHHmmssfff
    # ファイル名先頭に上記日時文字列を付与する
    $newfile = (JOIN-PATH $toPath ($prefix + "_" + $_.Name))
    try{
        Move-Item -LiteralPath $_.FullName $newfile
    }catch{
        Write-Output ('Error message : ' + $_.Exception.Message)
    }
}

powerhell カギ括弧付きのファイルをファイル名変更(もしくは移動)

ファイル名に[] (カギ括弧)があると、Move-Itemがうまく動作しないことに気が付いた。

powershell ISEなどでオプションのサジェストには表示されないが「-LiteralPath」が使えるようだ。

PS > Move-Item -LiteralPath [aaa]aaa.txt ccc.txt

PS > ls
    ディレクトリ:
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        2023/04/29     22:06             12 ccc.txt

検証

ファイルを作成

PS > echo "aho" > test.txt

PS > ls
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        2023/04/29     22:06             12 test.txt

カギ括弧付きのファイル名に変更

Move-Itemはtoファイル名にカギ括弧はOKみたい。

PS > Move-Item .\test.txt [aaa]aaa.txt

PS > ls
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        2023/04/29     22:06             12 [aaa]aaa.txt

カギ括弧つきファイル名を変更

空振りする。

PS > Move-Item [aaa]aaa.txt ccc.txt

PS > ls
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        2023/04/29     22:06             12 [aaa]aaa.txt

ダブルクォーテーションで括ってみる。

PS > Move-Item "[aaa]aaa.txt" ccc.txt

PS > ls
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        2023/04/29     22:06             12 [aaa]aaa.txt

シングルクォーテションで括ってみる。

PS > Move-Item '[aaa]aaa.txt' ccc.txt

PS > ls
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        2023/04/29     22:06             12 [aaa]aaa.txt

エスケープ(\)してみる。

PS > Move-Item \[aaa\]aaa.txt ccc.txt
Move-Item : コマンドレットの動的パラメーターを取得できません。指定されたワイルドカード文字パターンは無効です: [aaa
発生場所 行:1 文字:1
+ Move-Item \[aaa\]aaa.txt ccc.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Move-Item]、ParameterBindingException
    + FullyQualifiedErrorId : GetDynamicParametersException,Microsoft.PowerShell.Commands.MoveItemCommand

エスケープ+ダブルクォーテーション。

PS > Move-Item "\[aaa\]aaa.txt" ccc.txt
Move-Item : コマンドレットの動的パラメーターを取得できません。指定されたワイルドカード文字パターンは無効です: [aaa
発生場所 行:1 文字:1
+ Move-Item "\[aaa\]aaa.txt" ccc.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Move-Item]、ParameterBindingException
    + FullyQualifiedErrorId : GetDynamicParametersException,Microsoft.PowerShell.Commands.MoveItemCommand

エスケープ+シングルクォーテーション。

PS > Move-Item '\[aaa\]aaa.txt' ccc.txt
Move-Item : コマンドレットの動的パラメーターを取得できません。指定されたワイルドカード文字パターンは無効です: [aaa
発生場所 行:1 文字:1
+ Move-Item '\[aaa\]aaa.txt' ccc.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Move-Item]、ParameterBindingException
    + FullyQualifiedErrorId : GetDynamicParametersException,Microsoft.PowerShell.Commands.MoveItemCommand

エスケープ文字がバックスラッシュかな?と思って試す。

PS > Move-Item `[aaa`]aaa.txt ccc.txt

PS > ls
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        2023/04/29     22:06             12 [aaa]aaa.txt

いずれもダメでした。

Edge がAlt+Tabでうざいのを変更する

ある時気づいた。

ALT+TAB目的のアプリケーションにたどり着くまでに時間がかかるようになった。

理由はEdgeのTabが1つ1つALT+TABの一覧に表示されているため、目的アプリケーションまでのキー押下数が増えたこと。

設定を見ると「Edgeで最大5つのタブを開く」という謎設定になっていた。ここを変更すればよろし。

※ちなみに、Win+TabだとEdgeは1つしか表示されないので、microsoftは今後Win+Tabを使わせたいのかな?

・設定変更方法

設定ーシステムーマルチタスク

「AltキーとTabキー」の部分を変更する。

(”ウィンドウのみを開く”に変更する) 

Edgeでブラウザ内画面分割

ちょっと感動した記事があったのでメモ。

Edgeをブラウザ内で画面分割できる。

(例)

URL部分は、左が左の画面、右が右の画面のURLとなる。

大きなディスプレイを使っている人は、割と右側に余裕がある。 ブラウザを2つ並べてもいいのだけれど、1ブラウザで分割できれば、それはそれで利点もありそう。

・設定手順

  1. EdgeのURL部分に「edge://flags/#edge-split-screen」を入力してEnter
  2. 設定画面が表示されるので、「Microsoft Edge Split Screen」をEnabled(有効)にする
  3. ブラウザの再起動を促されるので、ブラウザの再起動をする
  4. ブラウザのアイコンメニューに分割マークが表示されるので、これを押下するとブラウザ内分割ができる
  5. 分割をやめる時は、再度この「分割」ボタンを押下する。(たぶん、左側だけが全表示される)
  6. 再度、「分割」ボタンを押下すると、履歴の中から右側に表示したいページを選択できる
  7. タブの追加を行ったときは、再度、ブラウザ分割をする必要あり(分割指定のスコープは当該タブのみ)

・参考
マルチタスクが楽々! デフォルトで画面分割できる有能ブラウザ2選【今日のワークハック】 | ライフハッカー・ジャパン

powershell タスクスケジューラ 「タスクの実行時に使うユーザー アカウント」の確認

とあるタスクのこの部分(タスクの実行時に使うユーザー アカウント)をpowershellで確認してみた。

・例として、タスクパス=\ の「My Backup Task」というタスクについて確認してみる。 (管理者権限のあるpowershellターミナルから実行している)

PS > ((Get-ScheduledTask -TaskPath \ | where TaskName -eq "My Backup Task" ).Principal).UserID
SYSTEM

全部のタスクを列挙したければ下記の通り。(同じく管理者権限のpowershell

Get-ScheduledTask -TaskPath \ | %{
    write-output ($_.TaskName + ":" + ($_.Principal).UserID);
}

コマンドラインでFirefox

ファイル名を指定して実行。

firefox https://www.yahoo.co.jp

powershellから。

> Start-Process "Firefox" -ArgumentList "-url https://www.yahoo.co.jp"

・その他のコマンドラインオプション
コマンドラインオプション - Mozilla | MDN