Cómo recorrer archivos que coinciden con comodines en un archivo por lotes

193

Tengo un conjunto de nombres de archivo base, para cada nombre 'f' hay exactamente dos archivos, 'f.in' y 'f.out'. Quiero escribir un archivo por lotes (en Windows XP) que pasa por todos los nombres de archivo, para cada uno debería:

  • Mostrar el nombre base 'f'
  • Realizar una acción en 'f.in'
  • Realice otra acción en 'f.out'

No tengo ninguna manera de enumerar el conjunto de nombres de archivo base, aparte de buscar * .in (o * .out) por ejemplo.

Luke Halliwell
fuente
10
Realmente no quiero ser este tipo después de 111/0 votos, pero su pregunta no muestra ninguna investigación en absoluto
phil294

Respuestas:

292

Suponiendo que tiene dos programas que procesan los dos archivos, process_in.exe y process_out.exe:

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

%% ~ nf es un modificador de sustitución, que expande% f solo a un nombre de archivo. Vea otros modificadores en https://technet.microsoft.com/en-us/library/bb490909.aspx (a mitad de la página) o solo en la siguiente respuesta.

Jim Buck
fuente
47
Use un solo '%' si escribe esto en la línea de comando. Sé que el OP no pregunta por la línea de comando, pero eso es lo que estaba buscando cuando esta pregunta apareció en la parte superior de mi búsqueda en Google. Otros pueden apreciar esta parte.
Jason
2
¿Podría explicar la sintaxis? La variable de bucle se declara %%f¿por qué es más %%~nftarde?
Coronel Panic
66
@ColonelPanic: hay un puñado de ~modificadores para hacer cosas, como en mi ejemplo, solo obtén el nombre del archivo. Es solo un hábito para mí usar eso en caso de que *haga el camino completo o algo así. Hay un puñado de estos modificadores (a mitad de la página): microsoft.com/resources/documentation/windows/xp/all/proddocs/…
Jim Buck
¿Qué pasa si el archivo y el directorio tienen espacios en ellos?
BKSpurgeon
3
Además, tenga en cuenta que la variable %% f debe ser una sola letra: aparecerán mensajes de error crípticos si intenta utilizar algo legible y significativo.
Bruce Dawson el
90

Puede usar esta línea para imprimir el contenido de su escritorio:

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

Una vez que tengas el %%I variable, es fácil ejecutar un comando sobre ella (solo reemplace la palabra echo con su programa)

Además, se ha mejorado la sustitución de referencias de variables FOR. Ahora puede usar la siguiente sintaxis opcional:

%~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

En los ejemplos anteriores %I PATH puede reemplazarse por otros valores válidos. los%~ sintaxis termina con un nombre válido de variable FOR. Elegir nombres de variables en mayúsculas como%I hace que sea más legible y evita la confusión con los modificadores, que no distinguen entre mayúsculas y minúsculas.

Puede obtener la documentación completa escribiendo FOR /?

Mark Ingram
fuente
Esto no parece funcionar. %%I was unexpected at this time.
Brad
44
@Brad si está usando esto en la línea de comandos (y no en un archivo por lotes), luego use en %Ilugar de%%I
doubleDown
1
Una respuesta mucho mejor que la aceptada. Todos los indicadores / modificadores incluidos en la respuesta y no un sitio web de terceros ( nadie quiere hacer clic en su enlace, Louis )
JustCarty
5

La forma más fácil, según lo veo, es usar un bucle for que llame a un segundo archivo por lotes para su procesamiento, pasando a ese segundo archivo el nombre base.

Según el para /? ayuda, basename se puede extraer usando la opción ingeniosa ~ n. Entonces, el script base leería:

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

Luego, en process.cmd, suponga que% 0 contiene el nombre base y actúe en consecuencia. Por ejemplo:

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

Puede haber una mejor manera de hacer esto en un script, pero siempre he sido un poco confuso sobre cómo extraer múltiples comandos en un solo bucle for en un archivo por lotes.

EDITAR: ¡Eso es fantástico! De alguna manera me había perdido la página en los documentos que mostraba que podía hacer bloques de varias líneas en un bucle FOR. Voy a tener que regresar y reescribir algunos archivos por lotes ahora ...

Nathan Fritz
fuente
4

Ampliando en la publicación de Nathans . Lo siguiente hará el lote de trabajo en un archivo por lotes.

@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
Martín
fuente
3

Hay una herramienta que generalmente se usa en los servidores MS (hasta donde puedo recordar) llamada forfiles :

El enlace anterior contiene ayuda, así como un enlace a la página de descarga de microsoft.


fuente
1

El siguiente código filtra los nombres de archivo que comienzan con una subcadena dada. Se podría cambiar para adaptarse a diferentes necesidades trabajando en la extracción de subcadenas de subfnombres y la declaración 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
Sandro Rosa
fuente
0

Hacer eco de f.in y f.out separará el concepto de qué hacer un bucle y qué no hacer cuando se usa en un bucle 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
)

Aunque no preguntó, una buena manera de pasar comandos a f.in y f.out sería ...

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

Un enlace a todos los comandos de Windows XP: enlace

Pido disculpas si no respondí esto correctamente. La pregunta fue muy difícil de leer para mí.

Z. Mickaels
fuente