7

Я на Windows 10 Enterprise x64. У меня есть следующая иерархия каталогов с BAT-файлом на самом внутреннем уровне:

C:\
  dir\
    my files\
      run.bat

BAT-файл содержит следующие строки:

@pushd %~dp0
@echo %~dp0
@popd

(значение и использование %~dp0 объяснено в разделе справки for /? и в этом ответ)

Если я запускаю BAT-файл из командной строки, текущим каталогом которой является C:\dir\my files , я получаю очень разумный результат:

C:\dir\my files>run.bat
C:\dir\my files\

Но если я вызову его из родительского каталога C:\dir , я получу:

C:\dir>"my files"\run.bat
C:\dir\my files\my files"\

А? Обратите внимание, что внутреннее имя каталога дублируется, и в конце есть несколько случайных символов "\ . Давайте попробуем это по-другому:

C:\dir>"my files\run.bat"
C:\dir\my files\my files\

Заблудшие символы исчезли, но имя каталога все еще дублируется. Чем это объясняется? Как я могу изменить BAT-файл так, чтобы он давал одинаковые выходные данные независимо от того, из какого каталога он был вызван?

Конечно, мой реальный сценарий более сложен, чем эта упрощенная версия. Значение %~dp0 объединяется с другими строками, присваивается переменным среды, передается в качестве аргумента другим сценариям и т.д.

2 ответа2

4

Это известная ошибка / дефект дизайна в cmd.exe - %~dp0 и варианты могут дать неправильный результат, если указан путь к пакетному сценарию.

Есть обходной путь. Вы можете надежно получить значение из подпрограммы CALLed (обратите внимание, что должен использоваться хотя бы один модификатор, такой как ~d , ~f и т.д., В противном случае вы получите подпрограмму :label)

@echo off
setlocal
pushd %~dp0
echo From main fails: "%~dp0"
call :test
popd
exit /b

:test
echo From subroutine OK: "%~dp0"

- ВЫБОР ВЫБОРА -

d:\dir>"my files\test.bat"
From main fails: "d:\dir\my files\my files\"
From subroutine OK: "d:\dir\my files\"
1

В качестве обходного пути сохраните каталог заранее:

set "dir=%~dp0"

Это связано с тем, что %0 действительно вызывается по пути (как argv arg 0), поэтому в ваших примерах это либо "my files"\run.bat либо "my files\run.bat" .

Когда вы делаете %~dp0 , cmd.exe создает полный путь относительно текущего каталога, а затем извлекает части, которые вы просили.

После pushd «полный путь» (%~f0) будет либо:

C:\dir\my files\my files\run.bat
C:\dir\my files\my files"\run.bat

... а затем обрежьте имя файла, чтобы получить результаты.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .