環境変数PATHを短い名前の形式に変換する


LibreOffice(17)setsdkenv_windows.batを修正のあとMakefileをmakeしようとしているのですがWindowsのパスにカッコや空白が出現してあちこちでひっかかってなかなか前に進めません。

環境変数PATHをすべて短い8.3式パスに変更するバッチファイル


MS-DOSの頃の8.3式の短いファイル名システムの正式名称はなんていうのでしょうね? FAT16?

そのころの方がコマンドラインはやりやすかったかもしれません。

でもWindows7 64bitにもちゃんと8.3式のファイル名システムが残っているのですよね。

ということでとりあえず環境変数PATHを短い名前に変換するバッチファイルを作ってみました。

変更したPATHはこのバッチファイルを呼び出したコマンドウィンドウでのみ有効です。
@echo off
set LF=^


set PATH=%PATH:;=!LF!%
setlocal enabledelayedexpansion
  for /f "delims=" %%i in ("%PATH%") do set PATH1=!PATH1!%%~fdsi;
  set PATH1=%PATH1:~0,-1%
endlocal & set PATH=%PATH1%
PATH
echo.
echo 環境変数PATH短い形式に変換しました。
echo このPATHはこのコマンドウィンドウでのみ有効です。
echo.
pause
結構あちこち参考にさせて頂いてここまでできました。

短いパス名への変換はバッチファイルの引数を%%iを%%~fdsiとするだけです。

まずつまずいたのはパスを一つずつ引数%%iに入れる方法。

PATHはセミコロン;で区切られています。
for /f "delims=;" %%i in ("%PATH%") do set PATH1=%%~fdsi;%PATH1%
こんな感じでPATH1に短い名前のパスの環境変数PATH1ができると思ったのですがこれはダメです。

in ("%PATH%")のなかの;で区切られた要素、つまりtokenの1番目しか得られません。
for /F "tokens=2,3 delims=/" %p in ("%DATE%") do @echo %p%q
For - DOS コマンド一覧にあるforの例です。

%DATE%がyyyy/mm/ddのとき/で区切られたtokenの2番目が%p、3番目が%qに代入されます。
for /f "tokens=1-26 delims=;" %%a in ("%PATH%") do (
  set PATH1=%%~fdsa;
  set PATH1=PATH1%%~fdsb;
  set PATH1=PATH1%%~fdsc;
                 ︙
)
こんな感じでがんばってコマンドを書けば26個までは対応できそうですけでスマートではないですね。

DICOM(10)GDCM:サブフォルダのdcmファイルも一括処理するバッチファイルが完成でやったようにファイルの検索ではin (リスト)の要素が一つずつできたのと比較して考えてみました。

で、わかったのはリストが改行コードで区切られていると順に%%iに代入されるということ。

即時展開と遅延展開を利用して改行コードを展開するタイミングを調整する


ということでまずPATHのなかみのセミコロン;を改行コードに置換します。

これも結構どうするのか頭を悩ましたのですがDOSのバッチで、テキストファイル中の文字を "文字列 + 改行"で置換 したい - Yahoo!知恵袋をみて解決しました。

環境変数PATHをすべて短い8.3式パスに変更するバッチファイルを行番号を使って解説していきます。
set LF=^


set PATH=%PATH:;=!LF!%
この2行目で変数LFに改行コードを代入しています。

キャレット^が改行コードなのではなく、そのあとに続く表示されていない改行コードをリテラル(データ)として扱うためのキャレットです。

最初はキャレット^自体が改行コードのことかと思っていました。

コマンドプロンプト %~% のエスケープ - happynowの日を読んでキャレットがしている意味が理解できました。

これによって変数LFに改行コードが代入されます。

バッチファイルを実行するとキャレットに続く改行コードは改行コードとは機能しないために3行目も同じ行として理解されます。

4行目から次のコマンドが有効になりそうな気がするのですが、やってみると2行分空けないとダメでした。

5行目で既存の環境変数PATHのなかのセミコロン;を!LF!という文字列に置換しています。

set PATH=%PATH:;=%LF%%とするとPATHの中で改行されてしまってエラーになります。
setlocal enabledelayedexpansion
  for /f "delims=" %%i in ("%PATH%") do set PATH1=!PATH1!%%~fdsi;
  set PATH1=%PATH1:~0,-1%
endlocal & set PATH=%PATH1%
DICOM(8)GDCM:バッチファイルの環境変数の即時展開と遅延展開で学習した即時展開と遅延展開を利用して変数を展開するとタイミングを調整しています。

setlocal enabledelayedexpansion~endlocalの中では%PATH%で置換した!LF!という文字列が展開されて改行コードになります。

こうすることにより7行目のforで%PATH%の各パスが一つずつ%%iに代入されてdoに続くコマンドが実行されます。

for /f "delims="で("%PATH%")のなか各行の区切り文字を無しに指定しています。

デフォルトでは空白が区切り文字になっているので"delims="としないと%%iには区切り文字までの部分しか代入されません。

do set PATH1=!PATH1!%%~fdsi;でPATH1に短い名前のパスをセミコロン;を区切り文字として順に加えています。

set PATH1=%PATH1:~0,-1%で最後の;を削除しています。

setlocal enabledelayedexpansion~endlocalの外に変数を持ち出す


setlocal enabledelayedexpansion
  for /f "delims=" %%i in ("%PATH%") do set PATH1=!PATH1!%%~fdsi;
  set PATH1=%PATH1:~0,-1%
endlocal
最初はこれでいいと思ったのですが、これではsetlocal~endlocalの中でやった処理結果がendlocal以降に反映されません。

バッチファイルで、setlocal~endlocal内での変数の値を外部に引き継ぎたい! - IIJIMASの日記

ここで教えて頂き解決しました。

endlocalと同じ行ではsetlocal~endlocalの中の変数!PATH1!を%PATH1%として展開できるのです。

ということでendlocal & set PATH=%PATH1%として!PATH1!をPATHに代入しなおすことで以降もPATHの内容が反映されます。

引き継ぎたい変数が複数あるときはendlocal & set PATH=%PATH1% & set PATH=%PATH2% という感じで&を繋いでいけばよいです。

実在しないフォルダは短い名前に変換されない


短い名前のパスに変換するバッチファイルを実行してみると短い名前に変換されていないフォルダ名があるのに気がつきました。
@echo off
set outfile=%~dp0short_PATH_list.txt
set LF=^


set PATH=%PATH:;=!LF!%
echo.>>%outfile%
echo %DATE%>>%outfile%
echo.>>%outfile%
setlocal enabledelayedexpansion
for /f "delims=" %%i in ("%PATH%") do echo %%~fdsi>>%outfile%
endlocal
echo %outfile%にリストを出力しました。
echo.
pause
これでshort_PATH_list.txtに変換したパスを書き出してみて調べてみました。

すると変換されていないフォルダ名は全て実在しないものでした。

私の場合5個もありました。

Java:Eclipseでコールグラフ(1)ispaceプラグインをインストールでやったように環境変数の変数PATHからこれらの存在しないフォルダのパスを手動で削除しました。

小さな枠をスクロールしていかないといけないので結構面倒です。

参考にしたサイト


【Windows】バッチファイルの引数 at softelメモ
バッチファイルで%%1を%%~fds1とすると短い名前のパスに変換できます。

For - DOS コマンド一覧
いろいろ例も載っていてわかりやすいです。

DOSのバッチで、テキストファイル中の文字を "文字列 + 改行"で置換 したい - Yahoo!知恵袋
改行コードをキャレットと遅延展開を使ってうまく扱っています。

DOSのバッチで、テキストファイル中の文字を置換したい - BIGLOBEなんでも相談室
文字列置換の方法。

コマンドプロンプト %~% のエスケープ - happynowの日
キャレット^の使い方。

BATファイルで文字列の切り出し
文字列の抽出の仕方。

バッチファイルで、setlocal~endlocal内での変数の値を外部に引き継ぎたい! - IIJIMASの日記
endlocal && set a=%a%とされていますがendlocal & set a=%a%でもうまくいきました。
PR

0 件のコメント:

コメントを投稿