lets say that i have test.txt with this lines
1
2
3
i need batch file to rewrite this file as
3
2
1
in new txt file
i tried this to copy last line
for /f "delims=" %%A in (ttt.txt) do set last=%%A
echo %last%>>ttt_lastline.txt
and this to delete last line
#echo off & setlocal EnableDelayedExpansion
set row=
for /F "delims=" %%j in (File.txt) do (
if defined row echo.!row!>> File.new
set row=%%j
)
but wasn't helpful
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "destdir=U:\destdir"
SET "filename1=100lines.txt"
SET "outfile=%destdir%\outfile.txt"
SET /a count=0
FOR /f "delims=" %%a IN (%filename1%) DO (
SET /a count+=1
SET "line[!count!]=%%a"
)
(
FOR /L %%a IN (%count%,-1,1) DO ECHO(!line[%%a]!
)>"%outfile%"
GOTO :EOF
You would need to change the setting of destdir to suit your circumstances.
I used a file named 100lines.txt containing some dummy data for my testing.
Produces the file defined as %outfile%
Using delayedexpansion, read each line into line[?] using !count!, then simply echo each line loaded in reverse order.
This is a Vbscript solution.
Create a file named reverse.vbs and use this as the code.
Dim Stack: Set Stack = CreateObject("System.Collections.Stack")
Do While Not WScript.StdIn.AtEndofStream
Stack.Push WScript.StdIn.ReadLine
Loop
WScript.StdOut.WriteLine Join(Stack.ToArray, vbCrLf)
Now to reverse your file execute this from a cmd prompt or a batch file.
type input.txt |cscript //nologo Reverse.vbs>>output.txt
#echo off
setlocal enabledelayedexpansion
for /f %%a in (forward.txt) do
(
set reversed=%%a !reversed!
)
for %%i in (!reversed!) do echo.%%i >> reversed.txt
goto :eof
Related
I really don't understand why the first batch script is working and second not. I need to use the second batch script as I need to add more conditional inside the loop.
The script counts the number of lines in .txt file and make a separate variable for each of the lines
this version is working
#echo off
setlocal EnableDelayedExpansion
for /f "tokens=2 delims='" %%B in ('type "output-mp3.txt"') do set /a "nlines+=1+0" && <con: set "_line!nlines!=%%~nB"
echo line 1 !_line1!
echo line 2 !_line2!
echo total number of lines !nlines! and name of the song !_line2!
pause
I need the add more things on the for loop so I need do (...) but is not working ..
#echo off
setlocal EnableDelayedExpansion
for /f "tokens=2 delims='" %%B in ('type "output-mp3.txt"') do (
set /a "nlines+=1+0" && <con: set "_line!nlines!=%%~nB"
echo line 1 !_line1!
echo line 2 !_line2!
echo total number of lines !nlines! and name of the song !_line2!
pause
)
output-mp3.txt contain
file '...\intro\Canal-1\Videos-10.mp3'
file 'F...Canal-1\Videos-10\0HDW0N3Q.mp3'
#echo off
setlocal EnableDelayedExpansion
for /f "tokens=2 delims='" %%B in ('type "output-mp3.txt"') do (
set /a "nlines+=1+0"
<con: set "_line!nlines!=%%~nB"
)
set _line
works for me - regardless of the number of lines in the file.
This is my first posting so if the format is not as it supposed to be please excuse me for this. (Suggestions for
improvement are welcome.)
I am trying to create a batchfile that will read last lines from logfiles and copy them to a new file.
Until now I have found here a way to read the last line.
Code would be something like:
for /f %%i in ('find /v /c "" ^< someFile.txt') do set /a lines=%%i
set /a startLine=%lines% - 1
more /e +%startLine% someFile.txt > lastLines.txt
The above code works for one file at a time. What I need is to read the last line from all files in a known list and add this line to a new .csv file.
I have been using the following code for getting the 4th entry in the logfiles but it returns every line of every logfile:
for /f %%x in (%list%) do for /f "delims=.txt, tokens=4" %%i in (%%x.txt) do echo %%x, %%i >> output.csv
What I would need is a sort of combination of both but I don't know how to combine them and make the complete last line be copied to the .csv file.
===
#Magoo:
Thanx for your reaction.
In every logfile can be 1 to >100 lines with comma separated information. Something like:
"LOGON,6-1-2015,12:43:39,USERNAME,HOSTNAME,,,,192.168.209.242,00:21:5A:2E:64:5E"
The last code with the 4th entry was used to get a list of all accounts that had logged in to the computers. This code gave me a very large list of all logon/logoff events on all computerlogs I checked in %list%.
In %list$ I had all the names of logfiles I wanted to be checked. This returned all lines.
For a new batchfile I need only the last logon/logoff entry and I want the whole last line.
So I have a .txt file with the hostnames of all computers I need to examine.
This .txt file will be read line by line via the variable %list%.
From every logfile I need only the last line copied to an output file.
===
I just tried the solution offered by JosefZ. Unfortunately this does not work for me yet. No lastlines are copied to the resultfile. In the code I removed the extra entry for possible lastlines for there are no empty lines in the logs, I also added an entry for the hostname I want to be available in the result. JosefZ had the filename there:
#ECHO OFF >NUL
#SETLOCAL enableextensions disabledelayedexpansion
type nul>output.csv
set "list=_listing.txt"
for /F "tokens=*" %%x in ('type "%list%"') do (
set "host=%%~x"
for /F "tokens=*" %%G in ('type "%%~x"') do set "lastline=%%G"
call :lline
)
:endlocal
#ENDLOCAL
goto :eof
:lline
set "filename=.\logs\%filename:&=^&%.txt"
echo %host%,%lastline%>>output.csv
goto :eof
The resultfile shows only the hostnames. I'll puzzle some more with this but all tips are welcome!
===
Got it!!!
#ECHO OFF >NUL
#SETLOCAL enableextensions disabledelayedexpansion
type nul>output.csv
set "list=_listing.txt"
for /F "tokens=*" %%x in ('type "%list%"') do (
set filename= :: *empty previous filename*
set lastline= :: *empty previous lastline*
set "host=%%~x"
set "filename=.\logs\%host%.txt" :: *creating the filename from path+hostname+extention*
for /F "tokens=*" %%G in ('type "%filename%"') do set "lastline=%%G"
call :lline
)
:endlocal
#ENDLOCAL
goto :eof
:lline
echo %host%,%lastline%>>output.csv
goto :eof
Your approach with line numbering could fail if a file has more trailing empty lines. Fortunately for /F loop ignores (does not iterate) empty lines; let's put to use this feature: in the script used next practices:
disabledelayedexpansion to allow ! in file names
set "list=_listing.txt" where the _listing.txt contains list of file names (full path and extension .txt including), one file name on one line: got by dir /b /s *.txt>_listing.txt
type nul>files\output.csv to empty the output file (optional)
set "lastline=!!!file empty!!!" to initialize variable %lastline%; could be set "lastline=" as well
call :lline to process variables %filename% and %lastline%
set "filename=%filename:&=^&%" to allow & in file names
The script is as follows:
#ECHO OFF >NUL
#SETLOCAL enableextensions disabledelayedexpansion
type nul>files\output.csv
set "list=_listing.txt"
for /F "tokens=*" %%x in ('type "%list%"') do (
set "filename=%%~x"
set "lastline=!!!file empty!!!"
rem the whole line
for /F "tokens=*" %%G in ('type "%%~x"') do set "lastline=%%G"
rem the fourth token only
rem for /F "tokens=4" %%G in ('type "%%~x"') do set "lastline=%%G"
call :lline
)
:endlocal
#ENDLOCAL
goto :eof
:lline
set "filename=%filename:&=^&%"
echo %filename% %lastline%
rem >>files\output.csv
goto :eof
Sample _listing.txt file:
d:\bat\files\1exclam!ation.txt
d:\bat\files\2exc!lam!ation.txt
d:\bat\files\11per%cent.txt
d:\bat\files\12per%cent%.txt
d:\bat\files\17per%Gcent.txt
d:\bat\files\18per%%Gcent.txt
d:\bat\files\21ampers&nd.txt
d:\bat\files\22ampers&&nd.txt
Output:
d:\bat>lastlines
d:\bat\files\1exclam!ation.txt 0 15.01.2015 1:52:28.48 -15072 20465
d:\bat\files\2exc!lam!ation.txt 6 15.01.2015 1:52:28.50 3250 16741
d:\bat\files\11per%cent.txt -8 15.01.2015 1:52:28.50 -3692 27910
d:\bat\files\12per%cent%.txt !!!file empty!!!
d:\bat\files\17per%Gcent.txt 0 15.01.2015 1:52:28.56 14508 12374
d:\bat\files\18per%%Gcent.txt 1 15.01.2015 1:52:28.56 30540 26959
d:\bat\files\21ampers&nd.txt 15.01.2015 1:22:50.18
d:\bat\files\22ampers&&nd.txt 15.01.2015 1:22:50.18
Honestly, all that ballast is for (possibly) trailing empty lines in files and for (possibly) ! and & in file names only; all could be done with
for /f %%x in (%list%) do for /f "skip=%startLine% tokens=4" %%i in (%%x) do echo %%x, %%i >> output.csv
You should use a simple FOR to iterate a list of values, not FOR /F.
Something like the following should work:
#echo off
setlocal enableDelayedExpansion
>>output.csv (
for %%F in (
"file1.log"
"file2.log"
"file3.log"
etc.
) do (
for /f %%A in ('find /v /c "" <%%F') do set /a skip=%%A-1
more +!skip! %%F
)
)
The quotes around the file names are there in case you get a name with spaces.
You could use your LIST variable if it looks something like
set LIST="file1.log" "file2.log" "file3.log" etc.
#echo off
setlocal enableDelayedExpansion
set LIST="file1.log" "file2.log" "file3.log" etc.
>>output.csv (
for %%F in (%LIST%) do (
for /f %%A in ('find /v /c "" <%%F') do set /a skip=%%A-1
more +!skip! %%F
)
)
If any of your file names contain the ! character, then you must toggle delayed expansion ON and OFF within your loop. Otherwise the delayed expansion will corrupt the names when %%F is expanded.
#echo off
setlocal disableDelayedExpansion
set LIST="file1.log" "file2.log" "file3.log" etc.
>>output.csv (
for %%F in (%LIST%) do (
for /f %%A in ('find /v /c "" <%%F') do set /a skip=%%A-1
setlocal enableDelayedExpansion
more +!skip! %%F
endlocal
)
)
I'm trying to read a file and output the lines of data into registry keys. The data collection works, but I don't understand the syntax required to increment the string values in the last loop.
#echo OFF
SETLOCAL DisableDelayedExpansion
FOR /F "usebackq skip=1 delims=" %%a in (`"findstr /n ^^ C:\GetSID.txt"`) do (
set "var=%%a"
SETLOCAL EnableDelayedExpansion
set "var=!var:*:=!" This removes the prefix
echo(!var:~76,63!>>C:\SIDoutput.txt
goto :EndLoop
)
:EndLoop
set /p SID= <C:\users\paintic\SIDoutput.txt
set KEY_NAME="HKEY_USERS\!SID!\Software\Microsoft\Windows NT\CurrentVersion\PrinterPorts"
set Counter=1
for /f %%x in (C:\users\paintic\Networkprinters.txt) do (
set "Line_!Counter!=%%x"
set /a Counter+=1
if !Counter!==3 (Echo %line_counter%)
)
set /a counter2=!counter!-3
set counter=1
The part below is what I can't get to work. I'm trying to write LINE_1, LINE_2 and LINE_3 values from the previous loop to increment via the loop below. So VALUENAME should equal LINE_1, TYPE should = LINE_2's value and DATA should = LINE_3 on the first run and keep going up by 1 until the loop finishes (end of the file read)
`for /L %%i in (1,1,%counter2%) do (
set ValueName=%Line_!counter!%
set /a counter+=1
set Type=%Line_!counter!%
set /a Counter+=1
set Data=%Line_!counter!%
set /a Counter+=1
echo !ValueName!
echo !Type!
echo !Data!
REG ADD %KEY_NAME% /v !ValueName! /t !Type! /d !Data! /f
)
ENDLOCAL
Pause`
On searching for errors in batch file it is always helpful to use in first line #echo on or remove #echo off or comment this line with rem to see what cmd.exe really executes.
Command line interpreter fails on lines with set VariableName=%Line_!counter!% as the interpreter does not know what to expand first. I think it is not possible to create dynamically the name of an environment variable and reference next the value of this environment variable. This approach most likely does not work ever.
However, what you want to achieve can be done much easier directly in second loop as the following example demonstrates:
#echo off
setlocal EnableDelayedExpansion
rem Create data for demo example.
set "KEY_NAME=HKEY_USERS\S-1-5-20\Software\Microsoft\Windows NT\CurrentVersion\PrinterPorts"
echo TestValue>"%TEMP%\Networkprinters.txt"
echo REG_SZ>>"%TEMP%\Networkprinters.txt"
echo Sample Data>>"%TEMP%\Networkprinters.txt"
echo AnotherValue>>"%TEMP%\Networkprinters.txt"
echo REG_DWORD>>"%TEMP%\Networkprinters.txt"
echo ^1>>"%TEMP%\Networkprinters.txt"
rem Now the loop follows which reads the data from the file line
rem by line and build the line for using command "reg.exe" to
rem add the data to registry of the user with the defined SID.
set Counter=1
for /f "usebackq delims=" %%x in ("%TEMP%\Networkprinters.txt") do (
if "!Counter!"=="1" (
set "ValueName=%%x"
) else if "!Counter!"=="2" (
set "ValueType=%%x"
) else (
set "ValueData=%%x"
rem Echo the command instead of really executing "reg.exe".
echo reg.exe ADD %KEY_NAME% /v "!ValueName!" /t !ValueType! /d "!ValueData!" /f
set Counter=0
)
set /a Counter+=1
)
rem Delete the text file created for demo example.
del "%TEMP%\Networkprinters.txt"
endlocal
This solution is much easier than what you have tried and can be maybe even more simplified.
I need to run a process on many items and the process takes a configuration file as input. The configuration file needs to be changed for each item at three different lines (1,2,17) with different extensions. I can read the configuration file into batch script as a text file but it should be saved with *.cfg configuration so that it can be used. I have put together the following pseudo code with pointers where I would need help for making it functioning batch script.
set inputline=1
set outputline=2
set xmlline=17
set infile=config.txt
set items=list.txt
for /f "delims=" %%a in (%items%) do (
echo.%%a
set curr=1
for /f "delims=" %%b in (%infile%) do (
if !curr!==%inputline% [replace this line in infile with "a".ext1]
if !curr!==%outputline% [replace this line in infile with "a".ext2]
if !curr!==%xmlline% [replace this line in infile with "a".ext3]
)
set /b "curr = curr + 1"
[save "infile".cfg]
)
"call" proccess.exe -config.cfg
)
And the configuration file:
sample.264
sample.yuv
test_rec.yuv
1
1
0
2
500000
104000
73000
leakybucketparam.cfg
1
2
2
0
1
sample.xml
3
Batch has no built in way of replacing a single line in a text file - however you can read the entire contents of the file, change the lines, then rewrite the file.
set file=config.txt
setLocal enableDelayedExpansion
set count=0
for /F "delims=~!" %%b in ('type %file%') do (
set /a count=!count!+1
set line!count!=%%b
)
set line1="a".ext1
set line2="a".ext2
set line17="a".ext3
del %file%
for /L %%c in (1,1,!count!) do echo !line%%c!>>%file%
pause
I slightly modified what I did here. I took out the check to see if the file exists, as you should be able to assume that it will.
Thanks unclemeat, it helped me to nail-down the following working code for me:
set file=config.cfg
set vdos=test.txt
setlocal enabledelayedexpansion
for /f "delims=" %%a in (%vdos%) do (
echo %%a
set count=0
for /F "delims=~!" %%b in ('type %file%') do (
set /a count=!count!+1
set line!count!=%%b
)
set line1=%%a%.264
set line2=%%a%.yuv
set line17=%%a%.xml
del %file%
for /L %%c in (1,1,!count!) do echo !line%%c!>>%file%
ldecod config.cfg
)
I need to iterate over files contained in a folder and extract the first line for each file. I've tried to get this writing two batch file - the first one overate over files:
FOR %%a in (D:\TEST_BAT\*.TXT) do (
call Estrai_Header.bat %%a %header%
#echo on
echo %header%
)
The second one (named Estrai_header.bat) extract the first line for the file (just passing it as parameter):
set header = ""
SET /A maxlines=1
SET /A linecount=0
FOR /F %%b IN (%1) DO (
IF !linecount! GEQ %maxlines% GOTO ExitLoop
set $2 = %2%%b
echo %2%
SET /A linecount+=1
echo %linecount%
)
:ExitLoop
exit /b
Estrai_Header.bat works correctly and prints for every file just the first row. But I cannot see the value of the first line extracted in the first batch (it prints a void string). What's wrong in these batch files?
Thanks in advance.
try this:
#echo off&setlocal
FOR %%a in (D:\TEST_BAT\*.TXT) do (
set "line="
for /f "usebackqdelims=" %%i in ("%%a") do if not defined line set "line=%%i"
setlocal enabledelayedexpansion
echo(!line!
endlocal
)