Як провести цикл через файли, що відповідають підстановці у пакетному файлі


193

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

  • Відобразити базову назву 'f'
  • Виконайте дію на 'f.in'
  • Виконайте ще одну дію на "f.out"

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


10
Я дійсно не хочу бути цим хлопцем після голосів 111/0, але ваше запитання не показує жодного повторного дослідження
phil294

Відповіді:


292

Якщо припустимо, що у вас є дві програми, які обробляють два файли, 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
Використовуйте один "%", якщо введіть це в командному рядку. Я знаю, що ОП не запитує про командний рядок, але це те, що я шукав, коли це питання з’явилося вгорі мого пошуку в 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змінну, легко виконати команду над нею (просто замініть слово ехо на вашу програму)

Крім того, була підсилена заміна 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, який викликає другий пакетний файл для обробки, передаючи другому файлу базове ім'я.

Згідно з /? довідку, базове ім'я можна витягнути за допомогою опції «nfty ~ n». Отже, базовий сценарій читав би:

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

Це може бути кращим способом зробити це за одним сценарієм, але я завжди був трохи туманним, як витягнути кілька команд в одну для циклу в пакетному файлі.

EDIT: Це фантастично! Я якось пропустив сторінку в документах, які показали, що ви можете робити багаторядкові блоки в циклі 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-серверах (наскільки я пам'ятаю) під назвою forfiles :

Посилання вище містить довідку, а також посилання на сторінку завантаження мікрософт.


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: посилання

Прошу вибачення, якщо не відповів на це правильно. Питання мені було дуже важко прочитати.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.