Как изменить текущий каталог внутри оператора IF и сослаться на его путь с помощью переменной среды CD?

Я пытаюсь установить приложение с моего компьютера под управлением Windows 10, используя adb, и мне нужно использовать команду cd перед установкой приложения.

Но я вижу странное поведение. Если я использую cd команда перед if Скажите, это работает хорошо. Но если я использую cd командование внутри if Скажите, это не работает.

Вот что я попробовал:

  1. Этот работает хорошо:

    cd %~f0\..\..\apps\app_sample\samples\sample_app\build\outputs\apk
    if "%arg1%" == "aaa" (
        adb install %CD%\sample_app-debug.apk
    )
    
  2. Это приводит к выполнению в ошибке:

    if "%arg1%" == "aaa" (
        cd %~f0\..\..\apps\app_sample\samples\sample_app\build\outputs\apk
        adb install %CD%\sample_app-debug.apk
    )
    

    Вывод ошибки:

    Не удалось стат
    C: \ Users \ ntuser \ Documents \ рабочее пространство \ команда \ скрипт \ sample_app-debug.apk:
    Данный файл или каталог отсутствует

    Похоже, он не сделал cd Команда в этом случае.

1 ответ

Решение

Всякий раз, когда интерпретатор команд Windows cmd.exe встречает начало командного блока, начинающегося с ( и заканчивая сопоставлением )весь блок предварительно обрабатывается перед тем, как команда, оставленная командному блоку, будет выполнена вообще. Это означает, что все переменные среды, использующие %variable% синтаксис заменяется текущим значением указанной переменной среды перед выполнением команды, которая впоследствии выполняет весь командный блок. Такое поведение можно увидеть при запуске командного файла из окна командной строки без @echo off будучи обычно наверху командного файла.

Это означает, что для вашего командного файла с командой IF и командным блоком нужно выполнить при условии, что это правда, что %CD% заменяется текущим каталогом перед выполнением команды IF, а также перед тем, как команда CD будет выполнена вообще.

Есть две возможности:

  1. явно включить отложенное расширение переменной среды и ссылаться на переменную среды в командном блоке с использованием синтаксиса !variable!
    или же
  2. не используйте командный блок с помощью GOTO или подпрограммы и CALL.

Решение 1 с включенным отложенным расширением переменной среды:

setlocal EnableDelayedExpansion
if "%arg1%" == "aaa" (
    cd "%~dp0..\apps\app_sample\samples\sample_app\build\outputs\apk"
    adb.exe install "!CD!\sample_app-debug.apk"
)
endlocal

Решение 2 с тем, чтобы вообще не использовать командный блок и вместо этого использовать GOTO:

if "%arg1%" == "aaa" goto AAA
rem Other commands
goto :EOF

:AAA
cd "%~dp0..\apps\app_sample\samples\sample_app\build\outputs\apk"
adb.exe install "%CD%\sample_app-debug.apk"
goto :EOF
rem Or use a different GOTO to continue processing somewhere else in batch file.

Другое решение 2 использует подпрограмму и команду CALL:

if "%arg1%" == "aaa" call :AAA
rem Other commands executed even if above condition is true.

rem Avoid a fall through to the subroutine below.
goto :EOF

:AAA
cd "%~dp0..\apps\app_sample\samples\sample_app\build\outputs\apk"
adb.exe install "%CD%\sample_app-debug.apk"
rem Exit the subroutine and continue on line below calling it.
goto :EOF

Но я думаю, что ваш код может быть еще проще, потому что, скорее всего, нет необходимости указывать файл *.apk с полным путем.

if "%arg1%" == "aaa" (
    cd "%~dp0..\apps\app_sample\samples\sample_app\build\outputs\apk"
    adb.exe install sample_app-debug.apk
)

И, возможно, также работает это:

if "%arg1%" == "aaa" adb.exe install "%~dp0..\apps\app_sample\samples\sample_app\build\outputs\apk\sample_app-debug.apk"

Лучше использовать здесь %~dp0 который ссылается на диск и путь пакетного файла, заканчивающийся обратной косой чертой вместо %~f0 который является именем командного файла с расширением файла и полным путем.

Например, с командным файлом C:\Temp\Test\Install.bat командная строка

cd "%~f0\..\..\apps\app_sample\samples\sample_app\build\outputs\apk"

приводит к выполнению

cd "C:\Temp\Test\Install.bat\..\..\apps\app_sample\samples\sample_app\build\outputs\apk"

и текущий каталог C:\Temp\apps\app_sample\samples\sample_app\build\outputs\apk после этой команды с действительно неверным именем каталога Install.bat в пути, который не является каталогом.

Командная строка

cd "%~dp0..\apps\app_sample\samples\sample_app\build\outputs\apk"

намного лучше, так как это приводит к выполнению

cd "C:\Temp\Test\..\apps\app_sample\samples\sample_app\build\outputs\apk"

что делает также C:\Temp\apps\app_sample\samples\sample_app\build\outputs\apk текущий каталог, но с совершенно правильным путем по сравнению с указанным выше cd командная строка.

Чтобы понять используемые команды и то, как они работают, откройте окно командной строки, выполните там следующие команды и полностью прочитайте все страницы справки, отображаемые для каждой команды.

  • call /?... объясняет %~dp0 а также %~f0,
  • cd /?
  • endlocal /?
  • goto /?
  • if /?
  • rem /?
  • set /?... объясняет задержку расширения переменной среды на примере IF и FOR.
  • setlocal /?

У меня не установлен ADB. Так что я могу только предположить, что это исполняемый файл с расширением файла .exe а не командный файл с расширением файла .bat или же .cmd что потребует использования call adb.bat ... или же call adb.cmd ... в этом командном файле.

Другие вопросы по тегам