ayuda programacion batch: uso del for /f

Iniciado por juntacadaveres, 3 Abril 2019, 22:31 PM

0 Miembros y 1 Visitante están viendo este tema.

juntacadaveres

me han mandado el siguiente ejercicio:

Crea un fichero batch que muestre el siguiente menú
BUSQUEDA DE REGISTROS
1.- Nombre
2.- Apellido
3.- Teléfono
4.- Salir
La opción 1 pedirá un valor. Buscará en el fichero AGENDA.TXT, en el campo nombre
cualquier registro que contenga la cadena especificada. Ejemplo: si busco BE, localizará los
registros BERTA, ALBERTO, ABELARDO... Por cada registro encontrado mostrará:
Nombre
NOMBRE
Apellido
APELLIDO
Teléfono
TELEFONO
Los diferentes registros se separarán por una línea de guiones.
La opción 2 y 3 funcionan de forma similar.
La opción 4 vacía las variables y sale del programa.


el contenido del fichero es el siguiente:


jose:morales:41254
bob:dylan:124544
pepito:jimenez:6651454
susana:ochoa:124454
guillermo:paredes:4575
susel:roca:21145
tomas:palermo:4544


y mi codigo es el siguiente:


@echo off
rem ejercicio 9
setlocal enabledelayedexpansion
:menu
set nomb=
cls
echo -------------------------
echo - BUSQUEDA DE REGISTROS -
echo -------------------------
echo.
echo 1. Nombre
echo 2. Apellido
echo 3. Telefono
echo 4. Salir
echo.
:opt
set opt=
set /p opt="Selecciona una opcion: "
if /i "%opt%"=="1" goto opt1
if /i "%opt%"=="2" goto opt2
if /i "%opt%"=="3" goto opt3
if /i "%opt%"=="4" goto opt4
echo la opcion no es valida
pause>nul
goto menu
:opt1
set /p nomb="Buscar campo nombre: "

for /F "tokens=1,2,3 delims=:" %%a in (agenda.txt) do (
   echo %%a %%b %%c | find "%nomb%"
)
pause>nul
goto menu
:fin


obviamente solo esta hecho hasta la primera parte
pero mi problema es que no funciona tal como me lo piden

ya que el resultado seria

NOMBRE:APELLIDO:TELEFONO
y a mi me lo piden de otra manera

nombre
NOMBRE
apellido
APELLIDO
telefono
TELEFONO

no sé como extraer el %%b ni el %%c en otro echo ya que ya no es posible usar el

|echo %%b find %nomb%

ya que ni en el segundo token ni en el tercero no hay nada que coincida con %nomb%
no se como hacerlo.... necesito ayuda, por favor

srWhiteSkull

#1
La verdad es que es una tontería, vas por buen camino pero te diré:

Código (bash) [Seleccionar]
...
for /F "tokens=1,2,3 delims=:" %%a in (agenda.txt) do (
   echo %%a %%b %%c | find "%nomb%"
)
...


Por medio de ésto estás extrayendo las tres columnas de cada fila (%%a, %%b y %%c), y el find al encontrar en alguna de éstas filas una cadena que sea igual a la que tengas en %nomb% la imprime. Bien, entonces, ésto no es correcto para lo que te pide el ejercicio pero no vas mal encaminado, porque si tuvieras un nombre en apellidos o si pusiéramos de nombre "roca", nos mostraría los datos de "susel", y no debería mostrar nada, ya que "roca" es el apellido. Vale, entonces lo que tienes que hacer sabiendo que %%a corresponde al nombre, que %%b corresponde al apellido y %%c al número, es que poner una opción según sea el caso y luego imprimirlo. Para evitar que find te imprima el echo tienes que redireccionar la salida a nul (find %patron% > nul ) y luego usar && para si el caso es que existe ese patrón, acompañado de la secuencia de comandos correspondiente, y || en caso de no existir el patron.

Ejemplo:
Código (bash) [Seleccionar]
...
for /F "tokens=1,2,3 delims=:" %%a in (agenda.txt) do (
   if [%opt%] equ [1] echo %%a | find "%nomb%" > nul && (printf "%%a\nNOMBRE\n%%b\nAPELLIDO\n%%c\nTELEFONO")
)
printf "\nFin de la busqueda."
pause
...


De esta forma excluyes el resto de columnas y sólo validas la fila que te interesa.

Quizás la variable %nomb% debería pasar a llamarse %cadena% o %patron%, y al principio pon condiciones para cambiar el mensaje de entrada según a la opción escogida.

También observe el detalle del uso del printf en vez del echo. Esto es debido a que printf acepta o permite el uso del carácter de salto de línea (\n), aunque también se podría solucionar poniendo 6 echos.

EdePC

:xD, ya me había hecho ilusiones con printf, pero veo que mi windows 8 no lo trae. Supongo que srWhiteSkull se refiere a Linux-Bash.

- En windows yo estaba planteándome el siguiente FOR:

Código (dos) [Seleccionar]
FOR /F "tokens=1,2,3 delims=:" %%a IN (agenda.txt) DO (
  ECHO %%a | FIND "%nomb%" >nul
  IF NOT ERRORLEVEL 1 (
    ECHO Nombre:
    ECHO   %%a
    ECHO Apellido:
    ECHO   %%b
    ECHO Telefono:
    ECHO   %%c
  )
)


-- Pero veo que el FOR de srWhiteSkull es más eficiente al matar varios pájaros de un solo tiro, aunque puede ser más complicado agregar más instrucciones según convenga, como validaciones, bifurcaciones, etc.

-- Mi implementación final sería:

Código (dos) [Seleccionar]
@ECHO OFF
REM ejercicio 9
:menu
CLS
ECHO -------------------------
ECHO - BUSQUEDA DE REGISTROS -
ECHO -------------------------
ECHO.
ECHO 1. Nombre
ECHO 2. Apellido
ECHO 3. Telefono
ECHO 4. Salir
ECHO.
SET "encontrado="
SET /P opt="Selecciona una opcion: "
IF %opt% EQU 1 GOTO opt1
IF %opt% EQU 2 GOTO opt2
IF %opt% EQU 3 GOTO opt3
IF %opt% EQU 4 GOTO opt4
ECHO Opcion no valida
GOTO reiniciar

:opt1
SET /P "patron=Buscar por campo Nombre: "
FOR /F "tokens=1,2,3 delims=:" %%a IN (agenda.txt) DO (
  ECHO %%a | FIND /I "%patron%" >nul && CALL :imprimir %%a %%b %%c
)
GOTO reiniciar

:opt2
SET /P "patron=Buscar por campo Apellido: "
FOR /F "tokens=1,2,3 delims=:" %%a IN (agenda.txt) DO (
  ECHO %%b | FIND /I "%patron%" >nul && CALL :imprimir %%a %%b %%c
)
GOTO reiniciar

:opt3
SET /P "patron=Buscar por campo Telefono: "
FOR /F "tokens=1,2,3 delims=:" %%a IN (agenda.txt) DO (
  ECHO %%c | FIND /I "%patron%" >nul && CALL :imprimir %%a %%b %%c
)
GOTO reiniciar

:opt4
SET "opt="
SET "patron="
SET "encontrado="
EXIT

:imprimir
SET "encontrado=SI"
ECHO --------------------
ECHO Nombre:
ECHO   %1
ECHO Apellido:
ECHO   %2
ECHO Telefono:
ECHO   %3
ECHO --------------------
GOTO:EOF

:reiniciar
IF NOT "%encontrado%"=="SI" ECHO No se han encontrado ocurrencias
PAUSE >nul
GOTO menu


juntacadaveres

#3
Hola, muchas gracias a ambos por tomaros la molestia de contestar. Creía que nadie lo haría pero habéis contestado rápido y eso me entusiasma a seguir programando.

Y que la variable se llame %patron% me parece bien pensado.
Mi profesor uso el errorlevel en el script pero yo no tenía su código copiado porque había tirado casi la toalla y estaba desanimado. Estaba de malhumor porque muy aparte que me siento casi al final de la clase y su hermosa letra en la pizarra eran factores que acentuaban mi malestar. Es un señor que sabe mucho de informática pero no sabe como transmitir esos conocimientos a los alumnos.
Me podéis explicar el funcionamiento de la variable errorlevel en este script por favor? creo que si lo entiendo aquí ya enteré casi el resto de lo que queda del curso.
Me podrían explicar para qué sirve el doble && y el doble ||
el call usado en el segundo script tiene la misma función que un goto??
es que nos dijo que no veríamos calls y no entiendo esta función.
Y otra cosa,  mi windows no detecta el comando printf. Muchas gracias por vuestro tiempo compañeros.

EdePC

- && comando y || comando también usan ERRORLEVEL, el primero ejecuta comando si ERRORLEVEL es 0 (todo correcto), el segundo ejecuta comando si ERRORLEVEL es 1 o más (algo no salió bien, o no encontró lo que se buscaba ...)

- No sé si hayan tocado el tema de ficheros Batch con parámetros: saludar.bat pepe luego el batch imprime: ECHO Hola %1, que es: Hola pepe

-- Pues CALL hace prácticamente lo mismo, en este caso llama a una etiqueta y le pasa parámetros: CALL:imrpimir %%a %%b %%c luego en la etiqueta se usan los parámetros dados con la sintáxis %1 %2 %3

-- Otra cosa a tener en cuenta es que cuando se usa CALL, una vez finalizadas las intrucciones de la etiqueta, en este caso imprimir que finaliza con un GOTO:EOF, automáticamente "se regresa" a la siguiente instrucción que viene luego de llamar a CALL, vamos es como llamar a un ECHO hola, imprime el hola y continúa el programa, lo mismo con el CALL, ejecuta el CALL y continúa el programa.

- Te recomiendo ver la siguiente referencia de comandos completa, está en inglés:

https://ss64.com/nt/call.html
https://ss64.com/nt/errorlevel.html
https://ss64.com/nt/find.html
https://ss64.com/nt/syntax-args.html
...

- Si tu profesor te ha dado documentación o ejercicios haber si los puedes compartir  :xD, ya que no muy normal que enseñen batch a nivel programación, siempre he visto que enseñan a nivel comandos básicos de consulta y búsqueda: dir, find, md, attrib, etc.

juntacadaveres

Cita de: EdePC en  4 Abril 2019, 16:46 PM
- && comando y || comando también usan ERRORLEVEL, el primero ejecuta comando si ERRORLEVEL es 0 (todo correcto), el segundo ejecuta comando si ERRORLEVEL es 1 o más (algo no salió bien, o no encontró lo que se buscaba ...)

- No sé si hayan tocado el tema de ficheros Batch con parámetros: saludar.bat pepe luego el batch imprime: ECHO Hola %1, que es: Hola pepe

-- Pues CALL hace prácticamente lo mismo, en este caso llama a una etiqueta y le pasa parámetros: CALL:imrpimir %%a %%b %%c luego en la etiqueta se usan los parámetros dados con la sintáxis %1 %2 %3

-- Otra cosa a tener en cuenta es que cuando se usa CALL, una vez finalizadas las intrucciones de la etiqueta, en este caso imprimir que finaliza con un GOTO:EOF, automáticamente "se regresa" a la siguiente instrucción que viene luego de llamar a CALL, vamos es como llamar a un ECHO hola, imprime el hola y continúa el programa, lo mismo con el CALL, ejecuta el CALL y continúa el programa.

- Te recomiendo ver la siguiente referencia de comandos completa, está en inglés:

https://ss64.com/nt/call.html
https://ss64.com/nt/errorlevel.html
https://ss64.com/nt/find.html
https://ss64.com/nt/syntax-args.html
...

- Si tu profesor te ha dado documentación o ejercicios haber si los puedes compartir  :xD, ya que no muy normal que enseñen batch a nivel programación, siempre he visto que enseñan a nivel comandos básicos de consulta y búsqueda: dir, find, md, attrib, etc.

Muchas gracias por la información.
Sí. compartiré todos los scripts y ejercicios que hayamos echo en este curso cuando acabe primero de asir porque capaz se de cuenta que he ido compartiendo la solución a sus ejercicios de programación en batch y conociéndolo capaz me suspende el módulo entero de IMSO (implantación de sistemas operativos).
De todos modos, seguro que me asaltarán más dudas sobre programación en batch que iré posteando en este foro a media que surjan. Un saludo.

juntacadaveres

#6
Hola tengo una duda en cuanto el errorlevel
si un errorlevel a cero significa que la acción que buscaba se realizó satisfactoriamente
porque en este codigo

Código (dos) [Seleccionar]
set /p parametro="Indique nombre a buscar: "
for /F "tokens=1,2,3 delims=:" %%a in (agenda.txt) do (
   echo %%a | find /I "%parametro%" >nul
   IF NOT ERRORLEVEL 1 (
       echo ---------------
       echo Nombre
       echo %%a
       echo Apellido
       echo %%b
       echo Telefono
       echo %%c
       echo ---------------
   )
)
pause>nul
goto menu


si cambiase el
IF NOT ERRORLEVEL 1

a por
IF ERROR LEVEL 0

el script me deja de funcionar. Por qué?
y en todo aso
el valor del errorlevel hace referencia a la ultima acción que se realizo verdad?
o sea, que podría usar varios errorlevels en el mismo script
pero sus valores apuntarían a diferentes comandos. No se como explicarme en esto ultimo.

EdePC

- Porque el ERRORLEVEL que trabaja en la sentencia IF es un poco diferente:

IF ERRORLEVEL 0 => Significa Si el ERRORLEVEL es 0 o mayor

IF ERRORLEVEL 1 => Significa Si el ERRORLEVEL es 1 o mayor

IF NOT ERRORLEVEL 0 => Significa Si el ERRORLEVEL es menor que 0

IF NOT ERRORLEVEL 1 => Significa Si el ERRORLEVEL menor que 1

- Por esto, en la documentación de ERRORLEVEL https://ss64.com/nt/errorlevel.html comentan que podría ser más humano usar la variable %ERRORLEVEL% en lugar de ERRORLEVEL puro y duro:

IF %ERRORLEVEL% EQU 0 => Significa Si el ERRORLEVEL es 0

IF %ERRORLEVEL% GTR 0 => Significa Si el ERRORLEVEL mayor que 0

-- PERO hay que tener cuidado cuando se usa EnableDelayedExpansion porque hay que poner !ERRORLEVEL! en lugar de %ERRORLEVEL%

https://ss64.com/nt/delayedexpansion.html