Как перебрать файлы, соответствующие шаблону в пакетном файле

194

У меня есть набор базовых имен файлов, для каждого имени «f» есть ровно два файла, «f.in» и «f.out». Я хочу написать командный файл (в Windows XP), который проходит через все имена файлов, для каждого он должен:

  • Показать базовое имя 'f'
  • Выполните действие на «f.in»
  • Выполните еще одно действие на «f.out»

У меня нет никакого способа перечислить набор базовых имен файлов, кроме как для поиска * .in (или * .out), например.

Люк Холливэлл
источник
10
Я действительно не хочу быть этим парнем после 111/0 голосов, но ваш вопрос не показывает никаких исследований
phil294

Ответы:

293

Предполагая, что у вас есть две программы, которые обрабатывают два файла, process_in.exe и process_out.exe:

for %%f in (*.in) do (
    echo %%~nf
    process_in "%%~nf.in"
    process_out "%%~nf.out"
)

%% ~ nf - это модификатор замещения, который расширяет% f только до имени файла. См. Другие модификаторы в https://technet.microsoft.com/en-us/library/bb490909.aspx (посередине страницы) или просто в следующем ответе.

Джим Бак
источник
47
Используйте один '%', если набираете это в командной строке. Я знаю, что OP не спрашивает о командной строке, но это то, что я искал, когда этот вопрос возник в верхней части моего поиска в Google. Другие могут оценить это немного.
Джейсон
2
Не могли бы вы объяснить синтаксис? Переменная цикла объявляется, %%fпочему это %%~nfпозже?
Полковник Паник
6
@ColonelPanic - есть несколько ~модификаторов для выполнения действий , как в моем примере, просто получить имя файла. Это просто привычка для меня использовать это на тот случай *, если путь полностью или что-то еще. Существует несколько таких модификаторов (в середине страницы): microsoft.com/resources/documentation/windows/xp/all/proddocs/…
Джим Бак,
Что делать, если в файле и каталоге есть пробелы?
BKSpurgeon
3
Также помните, что переменная %% f должна состоять из одной буквы - загадочные сообщения об ошибках будут появляться, если вы попытаетесь использовать что-то читаемое и осмысленное.
Брюс Доусон
90

Вы можете использовать эту строку для печати содержимого вашего рабочего стола:

FOR %%I in (C:\windows\desktop\*.*) DO echo %%I 

Если у вас есть %%Iпеременная, вы легко можете выполнить команду (просто замените слово echo на вашу программу)

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

%~I         - expands %I removing any surrounding quotes (")
%~fI        - expands %I to a fully qualified path name
%~dI        - expands %I to a drive letter only
%~pI        - expands %I to a path only (directory with \)
%~nI        - expands %I to a file name only
%~xI        - expands %I to a file extension only
%~sI        - expanded path contains short names only
%~aI        - expands %I to file attributes of file
%~tI        - expands %I to date/time of file
%~zI        - expands %I to size of file
%~$PATH:I   - searches the directories listed in the PATH
               environment variable and expands %I to the
               fully qualified name of the first one found.
               If the environment variable name is not
               defined or the file is not found by the
               search, then this modifier expands to the
               empty string

https://ss64.com/nt/syntax-args.html

В приведенных выше примерах %Iи PATH могут быть заменены другими действительными значениями. %~Синтаксис завершается допустимым именем переменной FOR. Выбор имен переменных в верхнем регистре, например, %Iделает его более читаемым и позволяет избежать путаницы с модификаторами, которые не чувствительны к регистру.

Вы можете получить полную документацию, набрав FOR /?

Марк Инграм
источник
Это не похоже на работу. %%I was unexpected at this time.
Брэд
4
@Brad, если вы используете это в командной строке (а не в командном файле), тогда используйте %Iвместо%%I
doubleDown
1
Гораздо лучший ответ, чем принятый. Все флаги / модификаторы, включенные в ответ, а не сторонний веб-сайт ( никто не хочет нажимать на вашу ссылку, Луи )
JustCarty
5

На мой взгляд, проще всего использовать цикл for, который вызывает второй пакетный файл для обработки, передавая этому второму файлу базовое имя.

По словам для /? справка, базовое имя может быть извлечено с использованием опции ~ nifty. Итак, базовый скрипт будет выглядеть так:

for %%f in (*.in) do call process.cmd %%~nf

Затем в process.cmd предположим, что% 0 содержит базовое имя, и действуйте соответственно. Например:

echo The file is %0
copy %0.in %0.out
ren %0.out monkeys_are_cool.txt

Возможно, есть лучший способ сделать это в одном скрипте, но я всегда немного сомневался в том, как использовать несколько команд в одном цикле for в пакетном файле.

РЕДАКТИРОВАТЬ: это фантастика! Я как-то пропустил страницу в документах, которая показала, что вы можете делать многострочные блоки в цикле FOR. Я собираюсь пойти придется вернуться и переписать некоторые командные файлы сейчас ...

Натан Фриц
источник
4

Расширение на пост Натана . Далее будет выполнено задание в одном пакетном файле.

@echo off

if %1.==Sub. goto %2

for %%f in (*.in) do call %0 Sub action %%~nf
goto end

:action
echo The file is %3
copy %3.in %3.out
ren %3.out monkeys_are_cool.txt

:end
Мартин
источник
3

Существует инструмент, обычно используемый в MS Servers (насколько я помню), называемый forfiles :

Ссылка выше содержит справку, а также ссылку на страницу загрузки Microsoft.


источник
1

Код ниже фильтрует имена файлов, начиная с заданной подстроки. Его можно изменить, чтобы он соответствовал различным потребностям, работая над извлечением подстроки и подстановкой IF:

echo off
rem filter all files not starting with the prefix 'dat'
setlocal enabledelayedexpansion
FOR /R your-folder-fullpath %%F IN (*.*) DO (
set fname=%%~nF
set subfname=!fname:~0,3!
IF NOT "!subfname!" == "dat" echo "%%F"
)
pause
Сандро Роза
источник
0

Повторение f.in и f.out будет разделять концепцию того, что зацикливать, а что не зацикливать при использовании в цикле for / f.

::Get the files seperated
echo f.in>files_to_pass_through.txt
echo f.out>>files_to_pass_through.txt

for /F %%a in (files_to_pass_through.txt) do (
for /R %%b in (*.*) do (
if "%%a" NEQ "%%b" (
echo %%b>>dont_pass_through_these.txt
)
)
)
::I'm assuming the base name is the whole string "f".
::If I'm right then all the files begin with "f".
::So all you have to do is display "f". right?
::But that would be too easy.
::Let's do this the right way.
for /f %%C in (dont_pass_through_these.txt)
::displays the filename and not the extention
echo %~nC
)

Хотя вы не спрашивали, хороший способ передать команды в f.in и f.out - это ...

for /F %%D "tokens=*" in (dont_pass_through_these.txt) do (
for /F %%E in (%%D) do (
start /wait %%E
)
)

Ссылка на все команды Windows XP: ссылка

Я прошу прощения, если я не ответил правильно. Мне было очень трудно читать этот вопрос.

З. Микаэльс
источник