きっとどこの現場でもある、ディレクトリの管理問題。
SVNのディレクトリ構成を見ていたら
なんで同じファイルを複数のディレクトリに置いてんだ?!
二重管理になるじゃん!!
ってなりまして。
管理上構成についてはどうしても譲れないらしいので、片方にはショートカットを置くことで同意を取りました。
が。
ファイルサーバーならまだしも、SVNってローカルに落としたら全員フォルダパス変わっちゃうんですよね。
ということでショートカットを相対パスで指定することにしたんですが、手作業だとこれがまためんどくさい。
調べたらVBScriptで作れそうだったので、コマンド的に使えるショートカット作成スクリプトを書いてみました。
→ オプション指定で絶対パスでも作成できるようにしました。
ソースはここに。
目次
ショートカットの作り方:手動
こんな構成でファイルを用意しました。
- C:\Users\hazhikko\Desktop\ファイル置き場
- サンプルファイル.jpg
- C:\Users\hazhikko\Desktop\ショートカットサンプル\ショートカット置き場
- サンプルファイル.jpg - ショートカット
GUIでショートカットを作る
まずは普通にショートカット作るとどうなんの?ってところを。
適当なファイルを右クリック>ショートカットの作成を選択すると作成できます。
画像のショートカットなのでアイコンも対象画像のものとなってますね。
こいつのプロパティを見てみると、リンク先に画像の絶対パスが指定されています。
相対パスのショートカットを作る
リンク先を相対パスに書き換えたらいいんじゃないの?
と思いきや、それだとエラーになってしまいます。
じゃあどうすんの?
リンク先を以下のように変更します。
1 |
%windir%\explorer.exe "..\..\ファイル置き場\サンプルファイル.jpg" |
%windir%\explorer.exeでエクスプローラを指定。
その引数に相対パスを渡してあげます。
出来上がりはこんな感じ。
エクスプローラのショートカットなのでアイコンもエクスプローラになってますが、クリックするとちゃんとサンプルファイル.jpgを開いてくれます。
ショートカットの作り方:自動
つまり、自動で相対パスのショートカットを作るには
- エクスプローラのショートカットを作成
- 引数に対象ファイルの相対パスを指定
ができればよさそうです。
ショートカットはVBScript(からのWScript)で作れるので書いてみました。
使い方
- makeLink.vbsを適当な場所に置く
- パスを通す
- 以下を実行
そのまま実行すると相対パスでのショートカットを作ります。
1 |
makeLink ショートカット対象のファイルのパス ショートカットを作成するフォルダのパス |
3つ目に -f オプションを付けると絶対パスで作ります。
1 |
makeLink ショートカット対象のファイルのパス ショートカットを作成するフォルダのパス -f |
真ん中のアイコンが自動作成したショートカットです。
1つ目の引数に指定したパスのショートカットを、相対パス指定で2つ目の引数の場所に作成します。
引数は絶対パスでも相対パスでもOK。
フォルダのショートカットも作れます。
ダイアログについてはループ処理するときには邪魔だと思うので、不要であれば以下の行を消してください。
→ コマンド打って毎回ダイアログ出るのも邪魔だと思うのでコメントアウトしました
1 |
WScript.Echo "作成しました:" & directory & "\" & targetFileName & "-ショートカット.lnk" |
ポイント説明
絶対パスを取得する
相対パスを絶対パスに変換したい場合は、FileSystemObjectを作ってGetAbsolutePathNameするだけで取得できます。
1 2 3 4 |
Set fso = createObject("Scripting.FileSystemObject") path = fso.GetAbsolutePathName(path) Set fso = Nothing ConvertToFullPath = path |
FileSystemObjectは他にも親ディレクトリ名を取得したり、ファイルを移動したりと機能がいろいろあります。
相対パスを取得する
VBScriptには相対パスを返してくれるメソッドがありません。。。
しょうがないので自作しました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
' 相対パスへの変換 ' param {string} base 基準となるパス ' param {string} target 相対パスに変換するパス ' return {string} 変換したパス(変換できない場合は空文字) Function ConvertToRelativePath(base, target) Dim baseFull: baseFull = ConvertToFullPath(base) Dim targetFull: targetFull = ConvertToFullPath(target) ' パスを配列に変換して階層を比較する Dim baseArray: baseArray = Split(baseFull, "\") Dim targetArray: targetArray = Split(targetFull, "\") ' 短い方の配列をループの基準にする Dim cnt If UBound(baseArray) < UBound(targetArray) Then cnt = UBound(baseArray) Else cnt = UBound(targetArray) End If ' 2つのパスを先頭からチェック ' 異なるディレクトリを見つけてそこから相対パスを作成する Dim relativePath: relativePath = "..\" For i = 0 To cnt If baseArray(i) <> targetArray(i) Then For j = i To UBound(baseArray) -1 relativePath = relativePath & "..\" Next Dim targetArray_() ReDim targetArray_(UBound(targetArray) - i) Dim k: k = 0 For j = i To UBound(targetArray) targetArray_(k) = targetArray(j) k = k + 1 Next relativePath = relativePath & join(targetArray_, "\") Exit For End If Next ConvertToRelativePath = relativePath End Function |
こんな引数が渡されたとして
1 2 |
base: C:\Users\hazhikko\Desktop\ファイル置き場\サンプルファイル.jpg target: C:\Users\hazhikko\Desktop\ショートカットサンプル\ショートカット置き場 |
それぞれ\区切りで配列に変換してループ。
差分があるところを探す。
1 2 |
base: [C:,Users,hazhikko,Desktop,ファイル置き場,サンプルファイル.jpg] target: [C:,Users,hazhikko,Desktop,ショートカットサンプル,ショートカット置き場] |
見つけたらこんな感じに変更して合体。
1 2 3 4 5 6 7 8 |
// 差分以下の部分だけ残す base: [ファイル置き場,サンプルファイル.jpg] // 差分以下のディレクトリの数+1を参照できる相対パスに target: ..\..\..\ // joinして相対パス完成 ..\..\..\ファイル置き場\サンプルファイル.jpg |
アルゴリズムの良し悪しは置いとく。
相対パス取得の関数がない以外に
- 三項演算子使えない
- 配列のスライスができない
などなど色々あって、最近のリッチな言語の便利さを知ったという。。。
噂だとVBScriptからJSを呼んであれこれできるらしいですが、今回はVBScriptだけで書いたので無駄に長くなりました。
ショートカットを作成する
ショートカットの作成はWScriptのCreateShortcut()で行います。
TargetPathにはエクスプローラのパス(%windir%\explorer.exe)
Argumentsに相対パスを指定してやります。
相対パスはスペースを含むパスが指定されるとバグりそうなので"で囲んでおきます。
1 2 3 4 5 6 7 |
Set ws = CreateObject("WScript.Shell") Set shortcut = ws.CreateShortcut(directory & "\" & targetFileName & "-ショートカット.lnk") With shortcut .TargetPath = EXPLORER_PATH .Arguments = """" & targetRelativePath & """" .Save End With |
ここにCreateShortcutのプロパティが載ってるんですが
RelativePath:ショートカットの相対パス(未実装のため呼び出してもエラーになる)
2007年(XP時代)の記事ということは、もしかして相対パス指定実装されてるのでは?!
と思ってやってみましたがダメでした。
相対パスで指定できたら、アイコンも元ファイルのものになりそうなんですけどねぇ。
IconLocationである程度は変えられそうですが、拡張子によってアイコン変える処理作るのが面倒なのでそのままにしてます。
感想:VBScriptはめんどくさい
いや、Shell batchと比べたらものすごく書きやすくて便利ではあるんですけど。
それでもPythonとかに比べると…ねぇ?
普段当たり前のように使ってる関数がなかったりするので、他の言語で代用できるならそっちを使うかなぁ。
OS関連の内容でもっと複雑なのを書くのであれば、C#とかVBとかで書いた方が便利なライブラリを使えるのでいいかもしれません。
コンパイルしなきゃいけなくなりますけどね。。。
JSを呼び出して使えるというので、次からはそっちをきちんと調べて書いてみようかなぁ。