Dir передан в Set

Dir передан в Set

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

Моя попытка:

Dir /B "C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1" | (set /p myVar= & set myVar)

После использования он выдает

myVar:1.14.4

План был в том, чтобы он входил и отдавал команду, поэтому я сделал это так

@echo off
Dir /B "C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1" | (set /p myVar= & set myVar)
echo e %myVar%
cmd /k

но все, что происходит, это

e

Что я делаю не так? И есть ли способ сделать это с FOR?

решение1

Что я делаю не так?

Все просто — вы пытаетесь использовать метод, который не может работать ;-) Невозможно использовать конвейерный вывод команды для установки переменных среды в родительской среде из-за особенностей работы конвейеров Windows.

Ваш скрипт выполняется в командном процессе — назовем его родительским.

Канал Windows запускает два дочерних командных процесса, каждый со своим собственным отдельным пространством среды. Левая часть канала выполняется в первом дочернем процессе, а правая — во втором. Канал отправляет вывод первого дочернего процесса в качестве ввода второму дочернему процессу. Он SET /Pуспешно определяет новую переменную myVar в дочернем процессе, и SET MYVARкоманда отображает значение. Отлично.

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

Существует множество удивительных побочных эффектов конструкции Windows Pipe, которые сбивают с толку любого, кто не до конца понимает механизм. Смотретьhttps://stackoverflow.com/q/8192318/1012053для получения дополнительной информации. Рекомендую прочитать вопрос и все ответы.

Есть ли способ сделать это с помощью FOR?

Да, правильный способ захватить вывод команды в переменную окружения — через FOR, в частности, FOR /Fкак показывает DavidPostill. Хотя в его коде есть одна определенная проблема, одна потенциальная проблема и одна неэффективность.

Нет необходимости использовать USEBACKQпри обработке вывода команды. Проще использовать обычную одинарную кавычку, 'чем обратную кавычку:for /f %%F in ('yourCommand') do ...

Ошибка заключается в использовании echo myVar:%myVar%в теле цикла FOR. Это отобразит значение myVar, которое существовало до запуска цикла, поскольку расширение процентов происходит при разборе строки, а весь цикл FOR разбирается за один шаг. Вам нужно будет включить отложенное расширение ( setlocal enableDelayedExpansion), а затем использовать , echo !myVar!чтобы увидеть значение, которое было установлено в цикле.

Существует потенциальная возможность другой проблемы - FOR /F разберет значение на токены, разделенные пробелами, и захватит только первый токен. Если имя вашего файла содержит пробелы, то вы не получите полное имя, если только не используете опцию DELIMS, чтобы не указывать разделитель.

for /f "delims=" %%F in (....) do .... 

Но нет необходимости использовать DIR /Bи FOR /F. Вы можете просто использовать ванильный FORцикл без этой /Fопции.

Например, следующий код просто выведет список всех файлов:

for %%F in ("C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1\*") do echo %%~nxF

Указывает ~nx, что следует использовать только имя файла и расширение, игнорируя диск и путь к папке.

Обычно нет необходимости использовать переменную окружения — просто используйте %%Fпеременную FOR внутри цикла для выполнения своей работы.

Но если вам по какой-то причине нужно значение вне цикла, вы, конечно, можете сделать это

for %%F in ("C:\Program Files (x86)\ServerMaster\Internals\Versions\Van1\*") do set "myVar=%%~nxF"

Но это захватит только последний файл, который итерируется. Переменная myVar будет перезаписываться с каждой итерацией. Ваш исходный дизайн захватил бы первый файл, который был перечислен (предполагая, что его можно было бы заставить работать). Ни то, ни другое не кажется хорошей идеей, если вы не знаете наверняка, что папка Van1 содержит только один файл.

Если вам нужно захватить все файлы в переменную(ые), то вам нужно будет использовать псевдомассив. Batch не имеет формальной концепции массива, но его можно легко эмулировать. Вы можете найти множество примеров, если просто выполните поиск в Интернете по запросу "batchfile array"

Связанный контент