I'm trying to make a script that delete especifics lines of a .txt file by it number. I alreay got it:
#echo off
for /f "skip=1delims=*" %%a in (test.txt) do (
echo %%a >>newfile.txt
) >nul
It works fine and delete the line number '1'. But if i put more lines to delete, it doesn't work, see below:
#echo off
for /f "skip=1,5,8) delims=*" %%a in (test.txt) do (
echo %%a >>newfile.txt
) >nul
What is worong?
as already noted in the comments, skip doesn't help. Instead add line numbers (with find /v /n "") and output the original line (token2) without the line number, if the line number (token1) is not in the list:
#echo off
(for /f "tokens=1,* delims=[]" %%a in ('type test.txt^|find /v /n ""') do (
echo/%%a|findstr /x "1 5 8" >nul || echo/%%b
))>newfile.txt
(findstr switch x is important to compare the whole number, so 2018 isn't found with findstr "1")
|| works as "if previous command (findstr) failed, then"
As suggested findstr and for /f are the tools to use.
I add in conditional execution on fail || or success &&
if findstr does not detect the current line number (produced by the /n option) enclosed in commas in the echoed skip variable the Line is written to newfile.
:: Q:\Test\2018\06\09\SO_50777309.cmd
#echo off
:: generate test.txt with Line1..10
(for /l %%A in (1,1,10) do #Echo=Line%%A) >test.txt
Set "skip=,1,5,8,"
(for /f "tokens=1,*delims=:" %%a in (' findstr /n "^" ^<test.txt'
) do Echo=%skip%|findstr ",%%a," 2>&1>NUL ||Echo=%%b
)>newfile.txt
type newfile.txt
Sample output
Line2
Line3
Line4
Line6
Line7
Line9
Line10
Here is a variant without a pipe (|), which should be faster. Also lines with leading colons (:) or brackets ([/]) should be treated correctly here:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "_FILE=test.txt"
set "_FNEW=newfile.txt"
set "_SKIP=,1,5,8,"
> "%_FNEW%" (
for /F "delims=" %%L in ('findstr /N "^" "%_FILE%"') do (
set "LINE=%%L"
for /F "delims=:" %%K in ("%%L") do (
setlocal EnableDelayedExpansion
if "!_SKIP!"=="!_SKIP:,%%K,=,!" (
echo(!LINE:*:=!
)
endlocal
)
)
)
endlocal
exit /B
Related
I have the below batch-file:
cd /d "T:\R\YOU"
for /r T:\R\YOU %%i in (.) do echo %%~nxi>>D:\MultiThreading\ReadFile.txt
cd /d D:\MultiThreading
rem I want to remove dots and spaces for the file content
findstr /v "." ReadFile.pbd >> 11.txt
findstr /v " " 11.pbd >> 12.txt
pause
I am getting the correct output from read file, however the output of 12.txt is empty, what I am doing wrong?
This is the output of ReadFile.txt file:
YOU
YOU 14.1.33333
YOU 14.1.44444
YOU 14.1.55555
YOU 14.1.44444
I want such output (I want to remove the first line):
YOU14133333
YOU14144444
YOU14155555
YOU14144444
The following code snippet read the file ReadFile.txt skipping the first line, removes spaces and dots from every line, and outputs the result into a file called ReturnFile.txt:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
> "ReturnFile.txt" (
for /F "usebackq skip=1 delims=" %%L in ("ReadFile.txt") do (
set "LINE=%%L"
setlocal EnableDelayedExpansion
set "LINE=!LINE: =!"
set "LINE=!LINE:.=!"
echo(!LINE!
endlocal
)
)
endlocal
exit /B
#Echo off
For /f "usebackq Tokens=1-10 delims=. " %%A in ("ReadFile.txt"
) Do If "%%B" Neq "" Echo:%%A%%B%%C%%D%%E%%F%%G%%H%%%I%%J
A bit primitive and rather short for answer.
UPDATE
Here's my full code:
cd "C:\Users"
DIR /A:D /S /B > "%appdata%\folder_overview.txt"
type "%appdata%\folder_overview.txt" | findstr /v AppData | findstr /v All.Users | findstr /v Public >> "%appdata%\newfolder.txt"
move "%appdata%\newfolder.txt" "%appdata%\folder_overview.txt"
:repeatuntilfilesizezero
set LINES=0
for /f "delims==" %%I in (%appdata%\folder_overview.txt) do (
set /a LINES=LINES+1
)
set /a LINES=LINES-1
more +%LINES% < "%appdata%\folder_overview.txt" >> "%appdata%\last_folder.txt"
Setlocal EnableDelayedExpansion
set content=
for /f "delims=" %%i in (%appdata%\last_folder.txt) do set content=!content! %%i
pause
cd %content%
type "%appdata%\folder_overview.txt" | findstr /v "%content%" >> "%appdata%\newfolder.txt"
move "%appdata%\newfolder.txt" "%appdata%\folder_overview.txt"
DEL "%appdata%\last_folder.txt"
FOR %%S IN (%appdata%\folder_overview.txt) DO set size=%%~zS
echo %size%
IF %size% gtr 0 echo goto :repeatuntilfilesizezero
IF %size% equ 0 echo "null"
pause
I noticed that it's totally worth that the last line is a blank line.
I just want the following:
list all folders
"cd" to the last folder in "folder_overview.txt" and delete the last line from the file
check if "folder_overview.txt" is empty
-> if not empty, just goto label ":repeatuntilfilesizezero"
-> if empty, goto exit
So finally "cd" step-by-step in all folders which are in "folder_overview.txt".
Currently the "goto :repeatuntilfilesizezero" does not work. It do not jumps to the label.
Hannir
To retrieve the non-empty last line of a text file, you do not need to count the lines and skip all but one with more. Simply use a for /F loop with a variable assignment instead, so the variable holds the last line finally:
> "%APPDATA%\last_folder.txt" (
for /F usebackq^ delims^=^ eol^= %%L in ("%APPDATA%\folder_overview.txt") do (
set "LINE=%%L"
)
setlocal EnableDelayedExpansion
echo(!LINE!
endlocal
)
Delayed variable expansion is used here to avoid trouble with some special characters like ^, &, ( and ) in the last line.
In case the file does not contain duplicate lines, the following code could be used to remove the last line:
> "%APPDATA%\folder_overwiew.txt" findstr /L /X /V /G:"%APPDATA%\last_folder.txt" "%APPDATA%\folder_overwiew.txt"
In case the file might contain duplicates, the following snippet could be used instead:
set "LINE="
> "%APPDATA%\folder_overwiew.txt" (
for /F usebackq^ delims^=^ eol^= %%L in ("%APPDATA%\folder_overview.txt") do (
setlocal EnableDelayedExpansion
if defined LINE echo(!LINE!
endlocal
set "LINE=%%L"
)
)
I can't detect what you want to do, but as you cd into every directory, I assume you want to do something in every folder in the tree:
#echo off
cd /d "c:\users"
for /f %%i in (' dir /s /b /ad ^|findstr /v "AppData All.Users Public" ') do (
pushd "%%i"
echo now working in: %%i
echo doing something here in %%~ni
popd
)
I want to store the result of a command in a variable in a for loop in a batch script. I want to loop through a series of .sql files, count how many lines each file consists of and sum up the line counts.
Here is my attempt so far:
#echo off
setlocal ENABLEDELAYEDEXPANSION
set /a count=0
set /a t=0
for /f %%a in ('dir /b *.sql') do (
#echo %%a <- THIS PRINTS THE FILE NAME
#set t=findstr /r /n "^" %%a | find /C ":" <- THIS IS INCORRECT
echo %t% <- I WANT TO PRINT THE LINE COUNT FOR THE FILE
#set /a count+=%t% <- INCREASE THE COUNTER
)
echo %count% <- PRINT TOTAL LINE COUNT
When I run
findstr /r /n "^" *.sql | find /C ":"
in a command window it works, and I know I could use that for the end objective, but this question is about the variable assignment.
Where is my mistake? The variable t is assigned the value 0 all the time.
UPDATE: (Still not working)
#echo off
setlocal ENABLEDELAYEDEXPANSION
set /a count=0
set /a t=0
for /f %%a in ('dir /b *.sql') do (
#echo %%a
for /L %%b in ('findstr /r /n "^" %%a ^| find /C ":"') do (
set /a count+=%%b
)
)
echo !count!
For anyone interested reading this later, here is the final (working version):
#ECHO off
SETLOCAL ENABLEDELAYEDEXPANSION
SET /a count=0
SET /a t=0
for /f %%a in ('dir /b *.sql') do (
#echo %%a
for /f %%b in ('findstr /r /n "^" %%a ^| find /C ":"') do (
set t=%%b
)
ECHO !t!
#SET /a count+=!t!
)
ECHO "Total:" !count!
#set t=findstr /r /n "^" %%a | find /C ":" <- THIS IS INCORRECT
doesn't work. It sets the variable t to the string findstr /r /n "^" %%a and filters the Output of the set command (which Outputs nothing) with | find /C ":", which Counts exactly Zero colons in nothing.
The best way of doing it, is:
for /f %%x in ('findstr /r /n "^" %%a ^| find /C ":"') do set t=%%x
Edit I was so focussed on repairing your code, that I didn't really realize, that you just want to count all lines of all *.SQL files. That's quite easy. No need for delayed expansion:
set count=0
for /f %%a in ('type *.sql 2^>nul ^| find /n /v ""') do set /a count+=1
echo %count%
2>nul prevents type to print the file names to the screen.
Edit2
my solution with 203 files, 47763 lines in total needs about 24 seconds. Aschipfl's edit2 solution about seven milliseconds. Impressive... find /c must have a really efficient method to count the lines.
My slightly changed code to use this capability:
set count=0
for /f %%a in ('type *.sql 2^>nul ^| find /c /n /v ""') do set /a count+=%%a
echo %count%
which also needs about 7ms. No big surprise, as it's basically the same code as Aschipfl's - just formatted differently.
There is no need to use findstr /N /R "^" to precede each line with line number and : and count the number of lines containing : afterwards.
To count the number of lines a text file contains, you only need to redirect it into find /C /V "", like this:
< "\path\to\file.txt" find /C /V ""
To use this within your for loop, you could do this:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set /A COUNT=0
set /A T=0
for /F "eol=| delims=" %%A in ('dir /B "*.sql"') do (
setlocal DisableDelayedExpansion
echo(%%~A
for /F %%B in ('^< "%%~A" find /C /V ""') do (
endlocal
set /A T=%%B
)
echo(!T!
set /A COUNT+=T
)
echo Total: %COUNT%
endlocal
exit /B
The toggling of delayed expansion is done to avoid trouble with exclamation marks ! in any of the *.sql file names, which would be ignored otherwise and the error message The system cannot find the file specified. would appear. Delayed expansion is only required because of the (debug) line echo(!T!; if you remove that, you can disable delayed expansion for the entire script.
Edit #1:
Here is a compacted variant of the above script, without any temporary variable T and with delayed expansion disabled:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set /A COUNT=0
for /F "eol=| delims=" %%A in ('dir /B "*.sql"') do (
for /F %%B in ('^< "%%~A" find /C /V ""') do (
echo(%%~A: %%B
set /A COUNT+=%%B
)
)
echo TOTAL: %COUNT%
endlocal
exit /B
And here is a script that uses a single for /F loop to retrieve the number of lines, which lets find search for the *.sql files like find /C /V "" "*.sql", then takes its output that looks like ---------- file.sql: 5 for instance, splits off the count after : and sums up all of them. This approach needs delayed expansion again:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set /A COUNT=0
for /F "eol=| delims=" %%A in ('find /C /V "" "*.sql"') do (
set "LINE=%%~A"
echo(%%~A
setlocal EnableDelayedExpansion
set /A T=!LINE:*: =!
for /F "delims=" %%B in ("!T!") do (endlocal & set /A COUNT+=%%B)
)
echo TOTAL: %COUNT%
endlocal
exit /B
Yes, there is a second for /F loop nested as well, but this is required for transferring the value of T over the endlocal barrier.
Edit #2:
Here is probably the best solution for determining the total number of lines over multiple files. This lets type output every line of all the *.sql files, which are then counted by find. Therefore the for /F loop iterates once only, so the overall performance of this script is quite great:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set /A COUNT=0
for /F "delims=" %%A in ('
2^>nul type "*.sql" ^| find /C /V ""
') do (
set /A COUNT+=%%A
)
echo TOTAL: %COUNT%
endlocal
exit /B
I have a number of text files that are always the same number of lines - 42 and always the same type of information on each line. Also each line starts with a header.
What I would like is a batch script to keep line 30 of the text file remove the others and save the file.
I have tried to look find the line based on the information between two line. In this case the heading on line 30 (Job Notes) and the heading on line 31 (Job Number) and then write the information to a new file.
Line 30 begins with
Job Notes= (information specifically about the job)
Line 31 begins with
Job Number=
This is the code I used (which i found elsewhere on this site) and i am getting no output at all. Have tried other ways as well so don't really have to use this method if you can see a better one, basically i just want line 30 to be the only information in the file.
#ECHO OFF
SETLOCAL
SET "sourcedir=C\Batch"
SET "destdir=C:\Batch\Extract"
for /f "tokens=1 delims=[]" %%a in ('find /n "Job Notes"^<"%sourcedir%\7099.txt" ') do set /a start=%%a
for /f "tokens=1 delims=[]" %%a in ('find /n "Job Number"^<"%sourcedir%\7099.txt" ') do set /a end=%%a
(
for /f "tokens=1* delims=[]" %%a in ('find /n /v ""^<"%sourcedir%\00007099.txt" ') do (
IF %%a geq %start% IF %%a leq %end% ECHO(%%b
)
)>"%destdir%\newfile.txt"
GOTO :EOF
Any help would be greatly appreciated.
David
Option 1, using findstr string numeration
for %%a in (*.log) do (
for /f "tokens=1,* delims=:" %%b in (
'findstr /n "^" "%%a" ^| findstr /b "30:"'
) do (
echo(%%c>"%%a"
)
)
Option 2, using for command skip lines
setlocal disabledelayedexpansion
for %%a in (*.log) do (
set "line="
for /f "usebackq skip=29 delims=" %%b in ("%%a") do if not defined line set "line=%%b"
setlocal enabledelayedexpansion
echo(!line!>"%%a"
endlocal
)
You want you the /N flag with FINDSTR:
FINDSTR /N /R ".*" *.txt | FINDSTR /R "\<30:" > out.txt
Explanation:
FINDSTR /N /R ".*" *.txt
finds every line (".*" with the regex flag /R) in every text file (*.txt) and appends its line number to the front (/N). This is then piped to
FINDSTR /R "\<30:"
which only grabs lines starting with (that's the \< bit) 30:.
#ECHO OFF
SETLOCAL
SET "sourcedir=C\Batch"
SET "destdir=C:\Batch\Extract"
for /f "skip=29tokens=1* delims==" %%a in ('type "%sourcedir%\7099.txt" ') do ECHO(%%b >"%destdir%\newfile.txt"&goto nextstep
:nextstep
GOTO :EOF
should do the job, finding line 30 (by skipping 29) then tokenising on the separating = and having output exactly one, going to the next step in your batch.
Having said that, however - you do realise that you are setting start and end using 7099.txt and then picking the data from 00007099.txt don't you? Does 00007099.txt exist?
And c:\batch seems a mighty strange place to store data files to me. Personally, I'd put batch files there (and include c:\batch into your PATH) but it's your system...
I need to create a batch file that searches through 2 texts. Captures a line of text in a variable (that contains at least one of 3 strings, but doesn't contain forth string) and its line number.
Searches through the second text and captures in another variable the line of text that exists on the line-number of the first variable.
I need to use the two lines-of-text (variable) after that as well.
I kind of managed through the first text reading, but not sure what I'm doing wrong in the second one:
#echo off
set "found="
for /f "tokens=1,* delims=[]" %%a in (' find /n /v "" ^< "%LocalDir%\list.txt" ') do (
echo "%%b"|findstr /i /c:"one two small" /c:"one two birds" /c:"one two strings" >nul && set found=1
if defined found echo "%%b"|findstr /v /c:"one two small red apples" >nul || set "found="
if defined found (
echo %%a found
#echo off & setLocal EnableDelayedExpansion
set var=%%b
set Line_num=%%a
endlocal
) else (
echo %%a NOT FOUND
)
set "found="
)
REM part2--------------------
for /f "delims=" %%d in (list1.txt) do (
set FullVersion=%%d
#echo off & setLocal EnableDelayedExpansion
for /f "tokens=1* delims=" %%e in ("%%d") do (
if !Line_num!==%%e
set var2=!FullVersion!
echo !var2!
)
)
endlocal
echo %var%
echo %var2%
Any help will be appreciated.
here is what I end up with as solution:
for /f "tokens=1,* delims=[]" %%a in (' find /n /v "" ^< "%LocalDir%\software_list.txt" ') do (
echo "%%b"|findstr /i /c:"Micro Focus Enterprise " /c:"Micro Focus Visual" /c:"Micro Focus COBOL" >nul && set found=1
if defined found echo "%%b"|findstr /v /c:"Micro Focus Enterprise Server for .NET" >nul || set "found="
if defined found (set LineNumber=%%a&set ProductName=%%b)
REM else (echo Main Micro Focus product NOT FOUND. Nothing to do. Exit.&exit /b)
set "found="
)
find "2." temp1.txt > temp3.txt
for /f "tokens=2,3 delims==" %%c in (temp3.txt) do (echo %%c >> %LocalDir%\software_list1.txt)
for /f "tokens=1*delims=[]" %%a in (' find /n /v "" ^< "software_list1.txt" ') do IF %%a==%LineNumber% SET ProductVersion=%%b
REM ECHO %LineNumber%
REM ECHO %ProductName%
REM ECHO %ProductVersion%
set ProductName=%ProductName:"=%
set ProductName=%ProductName: =%
set ProductVersion=%ProductVersion:"=%
set ProductVersion=%ProductVersion: =%
set out_file_name=%ProductName%_%ProductVersion%_%COMPUTER_NAME%
REM echo %out_file_name:"=%
Thanks a lot to everyone.
I see some problems in your code:
This block makes no sense, as it set variables in a new setlocal context and after the endlocal the variables are lost.
#echo off & setLocal EnableDelayedExpansion
set var=%%b
set Line_num=%%a
endlocal
In the second block you open a setlocal context for each iteration, that will result in a overflow error.
And the endlocal after the Part2 seems also to be contraproductive.
The line if !Line_num!==%%e creates always a syntax error
Btw. Why do you use #echo off inside your code? The frist one at the batch start should be enough.
You should only use one setlocal EnableDelayedExpansion at the beginning of the script.
You should only use DelayedExpansion toggling, if you have problems with exclamation marks.
You could use some echo's to see what happens, like
for /f "tokens=1* delims=" %%e in ("%%d") do (
echo Compare: !Line_num!==%%e
if !Line_num!==%%e set var2=!FullVersion!
echo !var2!
)
#echo off
set "found="
for /f "tokens=1*delims=[]" %%a in (
' find /n /v "one two small red apples" ^< "%LocalDir%\list.txt" ') do (
echo "%%b"|findstr /i /c:"one two small" /c:"one two birds" /c:"one two strings" >NUL
IF NOT ERRORLEVEL 1 SET lnbr=%%a&SET ltext=%%b
)
for /f "tokens=1*delims=[]" %%a in (' find /n /v "" ^< "list1.txt" ') do IF %%a==%lnbr% SET L1txt=%%b
ECHO(line number %lnbr%
ECHO(from LIST %ltext%
ECHO(from LIST1 %L1txt%
This should do what you want - if I understand correctly. Much better to show your data and an example of required output. Trying to fix code that DOESN'T do something undefined is frustrating.
#echo off
rem I need to create a batch file that searches through 2 text FILEs.
rem Captures a line of text in a variable (that contains at least one of 3
rem strings, but doesn't contain forth string) and its line number.
set Line_num=
for /F "tokens=1* delims=:" %%a in (
'findstr /N /I /C:"one two small" /C:"one two birds" /C:"one two strings" "%LocalDir%\list.txt"
^| findstr /V /C:"one two small red apples"' ) do (
echo %%a found
set var=%%b
set Line_num=%%a
)
REM part2--------------------
if defined Line_num (
rem Searches through the second text and captures in another variable
rem the line of text that exists on the line-number of the first variable.
for /F "tokens=1* delims=:" %%d in ('findstr /N "^" list1.txt') do (
if %Line_num% == %%d (
set var2=%%e
echo %%e
)
)
)
echo %var%
echo %var2%