Estrazione di linee specifiche (in base al numero di riga) utilizzando il file batch
-
21-12-2019 - |
Domanda
Ho bisogno di estrarre linee specifiche da un file di testo (input.txt). Ho già trovato una soluzione ma ho alcuni chiarimenti perché non funziona se utilizzato con setlocalenabledealyed expansion
. Di seguito è riportato l'esempio
My Input.txt (numbered using findstr /n)
. In questo esempio, ho bisogno di estrarre le linee tra la linea numero 27 a 39. Nel mio file batch completo, questi valori sono chiamati da un altro modulo.
1:[root]
2:ASKEHPPTEQWEIRAZOKXL
...
...
...
27:[parent2/child2]
28:NJ35CG5D9DEYXKMQKBJX
29:ZAZRMGB2E0KAG85FSPI3
30:E9046AQL44LV1R79OT8E
31:8OPXV1QYCTQVK34JZ2KV
32:3E32PWHGX5RGTFUXI9GC
33:H7DTDDFQZVGETGL764YU
34:174UOQMW35BCIQJNR1P8
35:7B3V0E9QXFQOM3NF08CZ
36:QH6FZVMKKGHKF0J8PB5O
37:QCRC90QCWWGAHRWBVMUI
38:4QPVEJW75GFW8DUM1PGU
39:[parent2/child3]
...
...
...
3000:[end]
.
1 ° Codice - Calling.bat - Utilizzo di CALL
@echo OFF
set st_ln=27
set end_ln=39
for /f "tokens=1,2 delims=:" %%a in (input.txt) do call :extract "%%a" "%%b"
goto :eof
:extract
set "ln=%~1"
set "sid=%~2"
if %ln% LEQ %st_ln% goto :eof
if %ln% GEQ %end_ln% goto :eof
echo.%sid%
goto :eof
:eof
.
2nd Codice - Local.bat Utilizzato con setlocalenabledelayedexpansion
REM @echo OFF
set st_ln=27
set end_ln=39
SETLOCAL ENABLEDELAYEDEXPANSION
for /f "tokens=1,2 delims=:" %%a in (input.txt) do (
set "ln=%%a"
set "sid=%%b"
if !ln! LEQ !st_ln! goto :eof
if !ln! GEQ !end_ln! goto :eof
echo.!sid!
)
:eof
.
Uscita - Calling.bat Funziona assolutamente bene. Ma Local.bat non restituisce alcun errore, ma itona il loop solo una volta. (Ho provato a sostituire! ST_LN! &! End_LN! Con% st_LN% &% END_LN%, ma ancora lo stesso problema) Perché? Cosa mi manca?
C:\Temp>calling.bat
NJ35CG5D9DEYXKMQKBJX
ZAZRMGB2E0KAG85FSPI3
E9046AQL44LV1R79OT8E
8OPXV1QYCTQVK34JZ2KV
3E32PWHGX5RGTFUXI9GC
H7DTDDFQZVGETGL764YU
174UOQMW35BCIQJNR1P8
7B3V0E9QXFQOM3NF08CZ
QH6FZVMKKGHKF0J8PB5O
QCRC90QCWWGAHRWBVMUI
4QPVEJW75GFW8DUM1PGU
C:\Temp>local.bat
C:\Temp>REM @echo OFF
C:\Temp>set st_ln=27
C:\Temp>set end_ln=39
C:\Temp>SETLOCAL ENABLEDELAYEDEXPANSION
C:\Temp>for /F "tokens=1,2 delims=:" %a in (input.txt) do (
set "ln=%a"
set "sid=%b"
if !ln! LEQ !st_ln! goto :eof
if !ln! GEQ !end_ln! goto :eof
echo.!sid!
)
C:\Temp>(
set "ln=1"
set "sid=[root]"
if !ln! LEQ !st_ln! goto :eof
if !ln! GEQ !end_ln! goto :eof
echo.!sid!
)
C:\Temp>
.
Domanda supplementare:
Come ho detto sopra, potrei ottenere il risultato atteso, ma voglio solo sapere se può essere migliorato. Voglio estrarre linee specifiche (le linee potrebbero essere ovunque nel file di input e il numero di linea che ho bisogno potrebbe essere da 1 a 20), dal file di input che potrebbe avere fino a 3000 linee. Attualmente nel codice sopra riportato utilizzando il ciclo per il ciclo e il controllo del numero di riga per ciascuna riga e quindi ipererà attraverso il loop per 3000 volte, il che potrebbe potenzialmente ritardare l'output. C'è qualche altro modo per evitare questo e ad accelerare lo script (potrebbe essere la ricerca della gamma "di ricerca")?
Soluzione
Il local.bat
non funziona perché quando viene lezionata la prima riga, con il numero 1 e la riga di partenza 27, la condizione if !ln! LEQ !st_ln! goto :eof
viene valutata come VERO e il comando goto
eseguito, lasciando il loop di for
.
Per la domanda supplementare, è possibile calcolare quante righe devono essere saltate all'inizio del file e quindi è possibile eseguire solo la linea finale.Poiché nessuna variabile viene modificata all'interno del loop, non è necessario alcuna necessità di espansione ritardata
set /a "skipLines=st_ln-1"
if %skipLines% gtr 0 (
set "skipLines=skip=%skipLines%"
) else (
set "skipLines="
)
for /f "%skipLines% tokens=1,2 delims=:" %%a in (input.txt
) do if %%a gtr %end_ln% ( goto :eof ) else (
echo(%%b
)
.
Il test if %skiplines% gtr 0
è necessario in quanto il loop for /f
non consente una clausola skip=0