PowerShellで、楽天カード家計簿(CSV)を読み込むのだ。

$FileName = "enavi_household_2019.csv"
# タイトルが無いCSVファイルにはタイトルをつけることができる。
$CsvTitle = @("年月日","摘要・購入店","種類","支払い","金額")

$Csv = Import-Csv $FileName -Encoding Default -Header $CsvTitle
$Csv | ForEach-Object{
$_."年月日"
$_."摘要・購入店"
$_."種類"
$_."支払い"
$_."金額"
}

CSVファイルはこれだけでオブジェクトとして取り込めました。 基本的には1行目は自動でタイトル行として読み込まれるらしい(試してない)ですが、上のサンプルの様に、-Headerで文字列配列を指定するとタイトルを作成できる。

Javaで言うとbean配列みたいな感じ。

ニッチな話だけども、WebObjectsをやったことがある人にわかり安く説明すると、Csvを読み込んでカラム名=値のNSDictionaryのNSArrayが出来上がる…みたいな。NextStepフレームワーク、使いやすかったんだけどなあ…。

PowerShellで、階層コピー

階層情報を保持したまま、単一ファイルをコピーする。

いろんなサイトでやっている、PowerShellによる階層コピーにチャレンジしてみた。これができれば、結構いろんなことができる。車輪の再発明

実行前

このような状態からtest1の中にある3.txtだけを、階層を保ったまま、test2コピーするのが目標。 結果、test2\hoge\hogehoge\hogehogehoge\3.txtを作りたい。 higehigeやhagehagehageは作らない。

E:\
├─test1
│  └─hoge
│      ├─higehige
│      └─hogehoge
│          ├─hagehagehage
│          │      9.txt
│          │
│          └─hogehogehoge
│                  1.txt
│                  2.txt
│                  3.txt
│                  4.txt
│
└─test2
想定結果

この様な形になって欲しい。

E:\
├─test1
│  └─hoge
│      ├─higehige
│      └─hogehoge
│          ├─hagehagehage
│          │      9.txt
│          │
│          └─hogehogehoge
│                  1.txt
│                  2.txt
│                  3.txt
│                  4.txt
│
└─test2
    └─hoge
        └─hogehoge
            └─hogehogehoge
                    3.txt
実行スクリプト

というわけでスクリプトを書いてみた。

$src_dir = 'E:\test1'
$dest_dir = 'E:\test2'

$src_file = '\hoge\hogehoge\hogehogehoge\3.txt'

#パスを結合する。
$src = Join-Path $src_dir $src_file
$dest = Join-Path $dest_dir $src_file
echo "コピー元:$src"

#対象がファイルであれば処理を実行する。
if(Test-Path $src -PathType Leaf){
    #転送先の親ディレクトリパスを取得
    $dir = Split-Path $dest -Parent
    echo "コピー先:$dir"
    #ディレクトリが無ければ作成する。
    if(!(Test-Path $dir -PathType Container)){
        #何階層だろうと一気に作れるみたい。
        New-Item $dir -itemType Directory
    }
    echo "ファイルをコピーします。:$src ==> $dir"
    #ファイルが既にあっても上書きコピー
    Copy-Item $src $dir -Force
}

「New-Item ~ -itemType Directory」で、深い階層まで一気に作れるのがわかったで助かった。最初はパスを分解して一つずつフォルダを作るつもりだったので。

2022-06-18追記 指定するパスはシングルクォートで。でないと$以降が消えたりとかあるので。

PowerShellで、ファイル一覧を取得する。

フルパスのファイル一覧を取得する。

2019-10-17追記 Resolve-Pathは-LiteralPathオプションの確認要。

Get-ChildItem -Recurse -file -Exclude .lnk | Sort-Object FullName |ForEach-Object{$_.FullName}

フルパス or 相対パスのファイル一覧をファイル出力する。

コメントのところで相対パス絶対パスを切り替える。

Get-ChildItem -Recurse -file -Exclude .lnk | ForEach-Object {
#$_.FullName
Resolve-Path -Relative $_.FullName
} | Out-File -FilePath D:\hoge.txt

ところで、Resolve-Path使うと行数ががっさりと減っちゃうんだけど、パスの中に"["とか"]"が入っていると消えちゃうみたい。ワイルドカード扱いされて結果無しになっちゃう。"["か"]"のどっちかだとコンバートエラーになる。絶対パス==>相対パスの切り替えにResolve-Pathを使うのはやめた方がよさそう。んで、書き換え。

Get-ChildItem -Recurse -file -Exclude .lnk | ForEach-Object {
#$_.FullName
$_.FullName.Replace($path, ".\")
} | Out-File -FilePath D:\hoge.txt

下手に正規表現とか使わずに、シンプルにいった方がよさそう。Windowsでやるなら頭にドライブ名が入るので、行頭からの一致とか気にする必要はないと思うけど、Linuxの場合は行頭からの一致に絞り込む必要はあると思う。

とりあえずのバックアップ設定。(PowerShellでrobocopy起動)

# コピー元のPATH
$basePath = "D:"
# コピー先のPATH
$destPath = "H:"
# ログファイル名(フルパス)
$logFile = $basePash + "\robocopy.log"


# /E :: 空のディレクトリを含むサブディレクトリをコピーします。
# /COPY:コピーフラグ :: ファイルにコピーする情報 (既定値は /COPY:DAT)。
#                       (コピーフラグ: D= データ、A= 属性、T= タイムスタンプ)。
#                       (S= セキュリティ =NTFS ACL、O= 所有者情報、U= 監査情報)
# /DCOPY:コピーフラグ :: ディレクトリにコピーする情報 (既定値は /DCOPY:DA)。
#                       (コピーフラグ: D= データ、A= 属性、T= タイムスタンプ)。
# /XF file [ファイル]... :: 指定された名前/パス/ワイルドカードに一致するファイルを除外します。
# /XJ :: 接合ポイントとシンボリック リンクを除外します (通常は既定で含まれます)。
# /R:n :: 失敗したコピーに対する再試行数: 既定値は 1,000,000。
# /V :: スキップされたファイルを示す詳細出力を作成します。
# /TS :: 出力にコピー元ファイルのタイム スタンプを含めます。
# /FP :: 出力にファイルの完全なパス名を含めます。
# /BYTES :: サイズをバイトで出力します。
# /LOG+:ファイル :: ログ ファイルに状態を出力します (既存のログ ファイルに追加します)。
# /TEE :: コンソール ウィンドウとログ ファイルに出力します。

robocopy $basePath $destPath /E /COPY:DAT /DCOPY:DAT /XF $logFile /XO /XJ /R:2 /W:5 /V /TS /BYTES /LOG+:$logFile /TEE

続・PhowerShellでフォルダ内のファイルハッシュを取得する

以前PowerShellでフォルダ内のファイルのハッシュ値を取得しましたが。 PhowerShellでフォルダ内のファイルハッシュを取得する - キジモナカズバ

いやいや。自分でForEach-Objectとかで回さんでもソートしてからExport-Csvでタブ区切りできるやん。ってやってみました。

$algorithm="SHA512"
$delimtter="`t"
$encoding="UTF8"

do{
$path = Read-Host "対象パスを入力してください"
}while(!(Test-Path $path) )

cd $path
$here = Convert-Path .
$file = Join-Path (Split-Path -Parent $here) ($algorithm + "_" + (Split-Path -Leaf $here) + ".txt")

echo $file

$hash = Get-ChildItem -File -Recurs | Get-FileHash -Algorithm $algorithm | Sort-Object Path | Export-Csv  -Delimiter $delimtter -Encoding $encoding -Path $file

アルゴリズムは変数に浮かしてSHA512とか使ってます。 Pathが絶対パスになっちゃってるのはどうしようもないのかな…。 Export-CSV -Confirmオプション付けて確認ダイアログ出してみたら、ボタン多すぎてわけわからなんかったのでやめた。 あとは進捗的なの出そうと思ったらForEach-Object使った方がやりやすそうね。

Javaの可変長引数を色々。

可変長引数色々。結局は配列になる。

お試しコード

public class Main {
    public static void main(String[] args) throws Exception {
        // Your code here!
        Main main = new Main();
        main.hoge("hoge","hige","hage");
    }
    private void hoge(String ... hoges){
        System.out.println(hoges.getClass().getName());
        for(int i = 0; i < hoges.length; i++){
            System.out.println(hoges[i]);
        }
        for(String ho: hoges){
            System.out.println(ho);
        }
    }
}

実行結果

[Ljava.lang.String;
hoge
hige
hage
hoge
hige
hage

参考

https://paiza.io/projects/266GxsDaHS0ypsxjC1m8fw?locale=en-us