2013-11-22 7 views
5

私はWindowsのバッチファイルでsetlocalがchdirと干渉するのはなぜですか?

setlocal 
chdir .. 

ディレクトリが変更されていないバッチファイルを実行しますが、私は

setlocal 
endlocal 
chdir .. 

を実行する場合、それは正常に動作する場合。これはまさにsetlocalで期待されるものでなければなりません。しかし、環境変数がどのように見えるかに関係するsetlocalの定義を読んだときは完全にはっきりしません。私はこれがsetlocalが実際に何をし、なぜchdirに干渉するのかを説明する良い機会であると期待しています。

答えて

2

実際には、SETLOCAL(help setlocalまたはsetlocal /?)のヘルプドキュメントがかなりうまく説明されています。明白でない唯一のことは、環境変数を含むだけでなく、現在のディレクトリ、ECHO状態、および遅延拡張および拡張状態も含むことであることは明らかである。もっとあるかもしれませんが、私はそれを今のところ考えることができません。

あなたをトリップされるものは、実際にかなりよく説明されている:「バッチスクリプトの終わりに達すると、暗黙のENDLOCALが、そのバッチスクリプトによって発行された未処理のSETLOCALコマンドのために実行される。」ではありません呼び出されたサブルーチンでも同じことが言えます。

バッチスクリプトが終了すると、暗黙のENDLOCALによってCHDIRの効果が「消去」されます。 2番目のコードの明示的なENDLOCALはルート環境に戻ってくるので、CHDIRは保存されます。


更新

カレントディレクトリは、通常%CD%を使用して現在の値を取得することができていても、環境変数ではありません。 SET CDを使って証明することができます。おそらく、 "環境変数CDが定義されていません"ということになります。 set "CD=some value"を使用して独自の真のCD変数を明示的に定義すると、%CD%は現在のディレクトリではなく、割り当てた値を返します。

元のSETLOCALコマンドは、古いCOMMAND.COMの日に遅延拡張または拡張を戻すことはありませんでした。 Enable/Disable DelayedExpansionとEnable/Disable Extensionsオプションは、CMD.EXEが導入されたときに追加されました。これは、MSがどのように機能を実装することを決めたかです。そうである必要はありませんでした。多くの点で、SETLOCAL/ENDLOCALを使わずにこれらの状態を制御できないことは残念です。私はしばしば、環境をローカライズせずに遅延拡張を有効または無効にできることを望みます。

+0

2つの重要な点があります。現在のディレクトリは環境変数で、スクリプトの最後に暗黙のENDLOCALがあり、元の環境を返します。今、私はsetlocalをよく理解することができます。なぜ、拡張された拡張がsetlocalで行われなければならないのか、それほど明確ではありません。それは別の質問ですが、なぜ私が失われたのかを説明しています.setlocalでの私の経験は、変数の評価方法を変更するために使用され、リンクが表示されないということでした。 –

+0

@ Dominic108 - 最新の回答をご覧ください。 – dbenham

+0

良い更新。私は現在のディレクトリ%__ CD __%がSETで変更できるとは考えていませんでしたが、それは環境の一部である変数だけです。 –

0

コマンドラインパラメータと内部ロジックの束に基づいてディレクトリを変更するために、この動作にバッチファイルを記述しました。

setlocalディレクトリとchangeディレクトリを使用する1つの方法は、バッチファイルを再帰的に呼び出し、文字列として宛先パスを返し、最上位の呼び出し元をcdにすることです。

この例では、バッチファイルを特定のディレクトリに変更するには、コマンドラインでPまたはPXのいずれかを取ります。

@echo off 
if not "%1"=="recurse" (
    for /f "delims=" %%i in ('%0 recurse %1') do cd %%i 
    exit /b 
) 
setlocal 
rem Do things here with "local" variables 
if "%2"=="p" (
    echo "c:\program files" 
) else if "%2"=="px" (
    echo "c:\program files (x86)" 
) 

注:

  • 私は「文字列を選択しました任意に再発する。
  • delimsは何も設定されていないため、パス内の空白文字で返された文字列を分割しません。
  • %0は、再帰するバッチファイルへのパスを返します。

ありがとうSO Batch equivalent of Bash backticks

関連する問題