Переменная в переменной cmd bat

Я импортирую переменные из config.txt в свой .bat файл.

Ниже приводится содержание моего config.txt:

param1 = %LOCALAPPDATA%\Programs  
param2 = %LOCALAPPDATA%\Programs\Myfolder

Это содержимое моего .bat файла:

for /f "delims = " %%L in (config.txt) do set %%L  
echo %param1%

Это выводит:

%LOCALAPPDATA%\Programs

Но я хочу, чтобы он вывел:

C:\Users\Alaska\AppData\Local\Programs

50
2

Ответы:

Решено

Если вы хотите еще один раунд расширения переменных, используйте команду call.

Если вам нужно, чтобы переменная содержала %LOCALAPPDATA%, используйте ее перед командой echo:

for /f "delims = " %%L in (config.txt) do set %%L
call echo %param1%

Если вы хотите, чтобы переменная была расширена до полного значения, используйте ее перед командой set:

for /f "delims = " %%L in (config.txt) do call set %%L
echo %param1%

Типовые решения уже опубликованы SomethingDark. Это работает в большинстве случаев.

Но у этого решения есть лишь некоторые недостатки.

  1. Использование call приводит к еще одному синтаксическому анализу командной строки, которая отвечает за расширение %VariableName% соответствующим значением ссылочной переменной среды. Но если строка файла/папки также содержит один или несколько символов %, которые являются частью имени папки/файла, а не ссылкой на переменную среды, знак процента (единственное или последнее появление) или все, что находится между двумя знаками процента, удаляется из строки. в результате получается неверная строка файла/папки.
  2. Использование команды call приводит к тому, что cmd.exe ищет файл с именем, указанным следующим, например set или echo, в текущем каталоге и далее во всех каталогах локальной переменной среды PATH с расширением файла, указанным в локальной переменной среды PATHEXT. Если файл с таким именем и соответствующим расширением действительно случайно найден, файл выполняется вместо внутренней команды cmdset или echo.
  3. Амперсанд в строке файла/папки можно интерпретировать как безусловный командный оператор вместо того, чтобы & являлся частью строки файла/папки.

Предположим, что каталог C:\Temp\Batch Test содержит файл config.txt со следующими строками:

param1=%LOCALAPPDATA%\Test1
param2=%TEMP%\Development & Test 100% (!)\Test2
param3 = "%TEMP%\Development & Test 100% (!) and really 100%\Test3"
param4=..\Data\Test4

В этом каталоге находится командный файл Test1.cmd со строками:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /f "delims = " %%L in (config.txt) do set %%L
set param
if defined param1 call echo %param1%
if defined param2 call echo %param2%
if defined param3 call echo %param3%
if defined param4 call echo %param4%
endlocal

Запуск пакетного файла Test1.cmd с текущим каталогом C:\Temp\Batch Test без файла с именем echo, найденного в текущем каталоге или в каталогах переменной среды PATH с расширением файла, указанным в переменной среды PATHEXT, приводит к выводу:

param1=%LOCALAPPDATA%\Test1
param2=%TEMP%\Development & Test 100% (!)\Test2
param3 = "%TEMP%\Development & Test 100% (!) and really 100%\Test3"
param4=..\Data\Test4
C:\Users\username\AppData\Local\Test1
C:\Users\username\AppData\Local\Temp\Development
'Test' is not recognized as an internal or external command,
operable program or batch file.
"C:\Users\username\AppData\Local\Temp\Development & Test 100\Test3"
..\Data\Test4

Проблемы следующие:

  1. Вывод строкового значения param2 неверен и приводит к интерпретации Test после & как дополнительной команды для запуска после echo, которая выводит только C:\Users\username\AppData\Local\Temp\Development . Строка param2 не заключена в " внутри config.txt, и командный файл не распознает это и не обрабатывает строку соответствующим образом.
  2. % (!) and really 100% в строке param3 интерпретируется как ссылка на переменную среды с именем (!) and really 100. Такой переменной среды нет, и поэтому эта часть имени папки ошибочно заменяется пустой строкой.
  3. Вывод param3 находится в окружении " и по этой причине работает, несмотря на & в строковом значении. Но для дальнейшей обработки пакетного файла нехорошо, если строки, назначенные переменным среды от param1 до param4, могут быть без двойных кавычек или с ними.
  4. Строка param4 по-прежнему содержит относительный путь к родительскому каталогу текущего рабочего каталога, что может быть как хорошо, так и плохо в зависимости от того, какой каталог установлен родительским процессом в качестве текущего рабочего при запуске cmd.exe для обработки пакетного файла и в зависимости от Пакетный файл предназначен для запуска с текущим каталогом или с каталогом пакетного файла.

Каталог C:\Temp\Batch Test также содержит командный файл с именем Test2.cmd со следующими строками:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /f "delims = " %%L in (config.txt) do call set %%L
set param
endlocal

Запуск пакетного файла Test2.cmd с текущим каталогом C:\Temp\Batch Test без файла с именем set, найденного в текущем каталоге или в каталогах переменной среды PATH с расширением файла, указанным в переменной среды PATHEXT, приводит к выводу:

param1=C:\Users\username\AppData\Local\Test1
param3 = "C:\Users\username\AppData\Local\Temp\Development & Test 100\Test3"
param4=..\Data\Test4

Проблемы следующие:

  1. Переменная окружения param2 вообще не определена.
  2. Переменная среды param3 содержит строку файла/папки, заключенную в ", в то время как две другие переменные не имеют окружения ", что может вызвать проблемы при дальнейшей обработке пакетного файла.
  3. % (!) and really 100% интерпретируется как ссылка на переменную среды с именем (!) and really 100. Такой переменной среды нет, и поэтому эта часть имени папки ошибочно заменяется пустой строкой.
  4. Строка param4 по-прежнему содержит относительный путь к родительскому каталогу текущего рабочего каталога, что может быть как хорошо, так и плохо в зависимости от того, какой каталог установлен родительским процессом в качестве текущего рабочего при запуске cmd.exe для обработки пакетного файла и в зависимости от Пакетный файл предназначен для запуска с текущим каталогом или с каталогом пакетного файла.

Все эти недостатки и проблемы не возникают при использовании следующего командного файла Test3.cmd, также хранящегося в каталоге C:\Temp\Batch Test:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
pushd "%~dp0" || exit /B 1
for /f "usebackq tokens=1* delims= = " %%G in ("%~dp0config.txt") do for /F delims^=^ eol^= %%I in ('echo "%%~H"') do set "%%G=%%~fI"
set param
popd
endlocal

Этот пакетный файл выполняется с помощью "C:\Temp\Batch Test\Test3.cmd", при этом текущий каталог C:\Users\username является типичным при открытии окна командной строки. Результат:

param1=C:\Users\username\AppData\Local\Test1
param2=C:\Users\username\AppData\Local\Temp\Development & Test 100% (!)\Test2
param3=C:\Users\username\AppData\Local\Temp\Development & Test 100% (!) and really 100%\Test3
param4=C:\Temp\Data\Test4

Третью командную строку можно удалить, если пакетный файл должен использовать текущий рабочий каталог, определенный вне командного файла. Эта строка гарантирует, что текущий рабочий каталог во время выполнения пакетного файла является каталогом, содержащим пакетный файл, который важен для param4.

Преимущества заключаются в следующем:

  1. Больше не используется команда call для расширения ссылок на переменные среды в строках файлов/папок в текстовом файле config.txt. Командный процессор Windows никогда не ищет файл с именем set или echo в текущем рабочем каталоге или в любом каталоге, указанном в переменной среды PATH, с расширением файла, указанным в переменной среды PATHEXT.
  2. Символ % в строке файла/папки, являющийся частью имени файла/папки, сохраняется даже при расширении ссылок на переменные среды, используемых в той же строке.
  3. Все четыре переменные среды определены без окружения ", даже если config.txt содержат строки без двойных кавычек и с двойными кавычками. На строки файла/папки, назначенные четырем переменным среды, теперь всегда можно ссылаться, используя окружение ", как это требуется для строк аргументов файла/папки неизвестной консистенции.
  4. Строка, назначенная переменной среды param4 с относительным путем, уже расширена до полного имени файла/папки, что полезно, если при дальнейшей обработке возникает ошибка, и строка файла/папки, назначенная param4, выводится в сообщении об ошибке. В этом случае пользователь получает четкую информацию, какой файл/папка вызывает проблемы.

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

Недостатком третьего решения является немного большее время выполнения, поскольку для каждой строки в config.txt в фоновом режиме выполняется еще один командный процесс с %ComSpec и опцией /c и командная строка, указанная во второй команде FOR внутри ' с командой echo.

Однако четвертую командную строку в третьем пакетном файле следует использовать, если пакетный файл предназначен для общего использования. За почти 30 лет я действительно видел все в строке, на которую ссылается %USERNAME%, которая является частью других предопределенных переменных среды, таких как USERPROFILE, APPDATA или LOCALAPPDATA. Пользователь может определить имя учетной записи, используя все символы, разрешенные в имени файла/папки. По этой причине необходимо написать сценарий для исправления обработки каждой возможной строки имени файла/папки.