There is a folder which contains some random files:
file1.txt
file2.exe
file3.cpp
file4.exe
How to SIMPLY display exe files connected with numbers like this:
1. file2.exe
2. file4.exe
And then I enter the number of the file, which I want to delete.. If it is even possible to do this simply..
Shortest bullet proof solution I can come up with. Like Anders, the DEL statement is disabled by the ECHO command. Remove the ECHO to make the menu functional.
#echo off
setlocal disableDelayedExpansion
for /f "delims==" %%A in ('set menu 2^>nul') do set "%%A="
for /f "tokens=1* delims=:" %%A in ('dir /b *.exe 2^>nul ^| findstr /n "^"') do (
set menu%%A=%%B
echo %%A. %%B
)
if not defined menu1 exit /b
set "delNum="
set /p "delNum=Delete which file (enter the number): "
setlocal enableDelayedExpansion
if defined menu!delNum! echo del "!menu%delNum%!"
The only thing I can think of that could go wrong is part of the menu could scroll off the screen if there are too many entries.
Additional messages can easily be incorporated. and an ELSE condition could be appended to the input validation to deal with invalid input.
A few subtle points of the code:
FINDSTR /N provides incrementing file number. Avoids need for delayed expansion or CALL within menu builder loop. Delayed expansion should not be enabled when expanding a FOR variable containing a file name because it will corrupt names containing !.
: is a safe FOR delimiter because a file name cannot contain :.
delNum is cleared prior to SET /P because SET /P will preserve existing value if <Enter> is pressed without entering anything.
Checking for the existence of the variable is the simplest way to validate the input. This is why it is critical that any existing MENU variables are undefined prior to building the menu.
Must use delayed expansion in IF DEFINED validation, otherwise space in input could crash the script (thanks Anders for pointing out the flaw in the original code)
DEL target must be quoted in case it contains spaces, even when delayed expansion is used.
Added test to make sure at least one menu entry exists before continuing. There may not be any .exe files left to delete.
#echo off
setlocal EnableDelayedExpansion
set i=0
for %%f in (*.exe) do (
set /A i+=1
set file[!i!]=%%f
echo !i!. %%f
)
set i=0
set /P i=File to delete:
del !file[%i%]!
Not exactly pretty but it gets the job done
#echo off
setlocal ENABLEEXTENSIONS DISABLEDELAYEDEXPANSION
goto main
:addit
set /A end=end + 1
set %end%=%~1
echo %end%. %~1
goto :EOF
:main
set end=0
for %%A in ("*.exe") do (
call :addit "%%~A"
)
if "%end%"=="0" goto :EOF
echo.&set idx=
set /P idx=Delete (1...%end%)
if not "%idx"=="" if %idx% GEQ 1 if %idx% LEQ %end% (
for /F "tokens=1,* delims==" %%A in ('set %idx% 2^>nul') do (
if "%idx%"=="%%~A" (
echo.Deleting %%~B...
rem del "%%~B"
)
)
)
Related
I am trying to create a menu with submenus which their names without extension come from the directory. However, I am unable to make a variable for choice as number. This code does not work anyhow. I would also want to display a number at the beginning of each file name in the menu; in fact, number of the files will also be one of the number that user selects as input. I could not overcome the problem.
#echo off
cd C:\Users\Murray\Documents\ConfigFiles\
for /f %%A in ('dir /a-d-s-h /b *conf ^| find /v /c ""') do set count=%%A
echo File count = %count%
for %%F in ("C:\Users\Murray\Documents\ConfigFiles\*.conf") do echo %%~nxF
set choice=
set /C /N="Please choice: "
if "%choice%" == "%count%" goto SUBMENU
if NOT EXIST "C:\Users\Murray\Documents\ConfigFiles\%choice%" goto NOFILE
:SUBMENU
Echo You are here
goto end
:NOFILE
echo %choice% could not be found.
goto END
:end
Any help will be appreciated.
Here's a quick example of a method touted in the answer by on no. It will print a number to the screen followed by the names of each file matching file extension, so will allow a large number of matching files, (although the end user may have to scroll a long list). Once a file is chosen, your end user then just types its corresponding number. The code should not proceed beyond the input request until a number matching one in the list is ENTERed.
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "src=C:\Users\Murray\Documents\ConfigFiles"
Set "ext=.config"
If Not Exist "%src%\*%ext%" Echo No file matches.& GoTo End
For /F "Delims==" %%G In ('"(Set #) 2>NUL"') Do Set "%%G="
For /F "Delims==" %%G In ('%SystemRoot%\System32\wbem\WMIC.exe OS Call /? ^|
%SystemRoot%\System32\find.exe "=="') Do Set "HT=%%G"
For /F "Tokens=1* Delims=:" %%G In ('Dir /B /A:-D "%src%\*%ext%" 2^>NUL ^|
%SystemRoot%\System32\findstr.exe /E /I /L /N "%ext%"'
) Do Set "#%%G=%%H" & Echo( %%G.%HT:~-1%%%H
If Not Defined #1 Echo No file matches.& GoTo End
:Opt
Echo(
Set "HT=" & Set "opt="
Set /P "opt=Enter the number for your chosen file>"
If Not Defined opt (GoTo Opt) Else Set "opt=%opt:"=%"
Set # | %SystemRoot%\System32\findstr.exe /B /L "#%opt%=" 1>NUL || GoTo Opt
SetLocal EnableDelayedExpansion
For %%G In ("!#%opt%!") Do EndLocal & Set "opt=%%~G"
#Rem Your code goes below here
Echo(& Echo You Selected %opt%
#Rem Your code ends above here
:End
Setlocal EnableDelayedExpansion & For /F "Tokens=1,2" %%G In ("!CMDCMDLINE!"
) Do Endlocal & If /I "%%~nG" == "cmd" If /I "%%~H" == "/c" Echo(& Echo Press^
any key to exit.&Pause 1>NUL
All you need to do is to modify the variables values on lines 4 and 5, if necessary, in order to test it. I will not be supporting changes or additions beyond that. Once you have tested the code, you may insert your code between lines 25 and 29, replacing the example line I left there for your test.
Batch's limitations are to blame for sub-par corrections to this question.
Here's the best I could whip up in a few seconds:
#echo off
:one
cls
cd C:\Users\Murray\Documents\ConfigFiles\
for %%F in ("C:\Users\Murray\Documents\ConfigFiles\*.conf") do echo %%~nxF
echo.
echo Enter Configuration Name:
set/p "prompt=>"
if exist %prompt%.txt goto :two
if exist %prompt% goto :two
cls
echo File not found
pause >NUL
goto :one
:two
cls
REM When file is found, this code will run
pause >NUL
The set command does not prompt for user input unless specified with the /p switch. To make your code more friendly, i'd also recommend to prompt for the filepath earlier on in the code.
EDIT: A few alternative solutions: Declare the 9th option of the prompt of the choice command as a "second page" or "more" option. This would really be a pain for the user in a directory with tens or hundreds of files. Another; you can assign an integer to each file that matches your quasi-query and echo them before each filename on the screen, then allow the user to input the number to get that file. That seems fairly efficient, and if you'd like to explore one or both of those alternates I can help (if you need it).
Is it possible to remove duplicate rows from a text file? If yes, how?
Sure can, but like most text file processing with batch, it is not pretty, and it is not particularly fast.
This solution ignores case when looking for duplicates, and it sorts the lines. The name of the file is passed in as the 1st and only argument to the batch script.
#echo off
setlocal disableDelayedExpansion
set "file=%~1"
set "sorted=%file%.sorted"
set "deduped=%file%.deduped"
::Define a variable containing a linefeed character
set LF=^
::The 2 blank lines above are critical, do not remove
sort "%file%" >"%sorted%"
>"%deduped%" (
set "prev="
for /f usebackq^ eol^=^%LF%%LF%^ delims^= %%A in ("%sorted%") do (
set "ln=%%A"
setlocal enableDelayedExpansion
if /i "!ln!" neq "!prev!" (
endlocal
(echo %%A)
set "prev=%%A"
) else endlocal
)
)
>nul move /y "%deduped%" "%file%"
del "%sorted%"
This solution is case sensitive and it leaves the lines in the original order (except for duplicates of course). Again the name of the file is passed in as the 1st and only argument.
#echo off
setlocal disableDelayedExpansion
set "file=%~1"
set "line=%file%.line"
set "deduped=%file%.deduped"
::Define a variable containing a linefeed character
set LF=^
::The 2 blank lines above are critical, do not remove
>"%deduped%" (
for /f usebackq^ eol^=^%LF%%LF%^ delims^= %%A in ("%file%") do (
set "ln=%%A"
setlocal enableDelayedExpansion
>"%line%" (echo !ln:\=\\!)
>nul findstr /xlg:"%line%" "%deduped%" || (echo !ln!)
endlocal
)
)
>nul move /y "%deduped%" "%file%"
2>nul del "%line%"
EDIT
Both solutions above strip blank lines. I didn't think blank lines were worth preserving when talking about distinct values.
I've modified both solutions to disable the FOR /F "EOL" option so that all non-blank lines are preserved, regardless what the 1st character is. The modified code sets the EOL option to a linefeed character.
New solution 2016-04-13: JSORT.BAT
You can use my JSORT.BAT hybrid JScript/batch utility to efficiently sort and remove duplicate lines with a simple one liner (plus a MOVE to overwrite the original file with the final result). JSORT is pure script that runs natively on any Windows machine from XP onward.
#jsort file.txt /u >file.txt.new
#move /y file.txt.new file.txt >nul
you may use uniq http://en.wikipedia.org/wiki/Uniq from UnxUtils http://sourceforge.net/projects/unxutils/
Some time ago I found an unexpectly simple solution, but this unfortunately only works on Windows 10: the sort command features some undocumented options that can be adopted:
/UNIQ[UE] to output only unique lines;
/C[ASE_SENSITIVE] to sort case-sensitively;
So use the following line of code to remove duplicate lines (remove /C to do that in a case-insensitive manner):
sort /C /UNIQUE "incoming.txt" /O "outgoing.txt"
This removes duplicate lines from the text in incoming.txt and provides the result in outgoing.txt. Regard that the original order is of course not going to be preserved (because, well, this is the main purpose of sort).
However, you sould use these options with care as there might be some (un)known issues with them, because there is possibly a good reason for them not to be documented (so far).
The Batch file below do what you want:
#echo off
setlocal EnableDelayedExpansion
set "prevLine="
for /F "delims=" %%a in (theFile.txt) do (
if "%%a" neq "!prevLine!" (
echo %%a
set "prevLine=%%a"
)
)
If you need a more efficient method, try this Batch-JScript hybrid script that is developed as a filter, that is, similar to Unix uniq program. Save it with .bat extension, like uniq.bat:
#if (#CodeSection == #Batch) #then
#CScript //nologo //E:JScript "%~F0" & goto :EOF
#end
var line, prevLine = "";
while ( ! WScript.Stdin.AtEndOfStream ) {
line = WScript.Stdin.ReadLine();
if ( line != prevLine ) {
WScript.Stdout.WriteLine(line);
prevLine = line;
}
}
Both programs were copied from this post.
set "file=%CD%\%1"
sort "%file%">"%file%.sorted"
del /q "%file%"
FOR /F "tokens=*" %%A IN (%file%.sorted) DO (
SETLOCAL EnableDelayedExpansion
if not [%%A]==[!LN!] (
set "ln=%%A"
echo %%A>>"%file%"
)
)
ENDLOCAL
del /q "%file%.sorted"
This should work exactly the same. That dbenham example seemed way too hardcore for me, so, tested my own solution. usage ex.: filedup.cmd filename.ext
Pure batch - 3 effective lines.
#ECHO OFF
SETLOCAL
:: remove variables starting $
FOR /F "delims==" %%a In ('set $ 2^>Nul') DO SET "%%a="
FOR /f "delims=" %%a IN (q34223624.txt) DO SET $%%a=Y
(FOR /F "delims=$=" %%a In ('set $ 2^>Nul') DO ECHO %%a)>u:\resultfile.txt
GOTO :EOF
Works happily if the data does not contain characters to which batch has a sensitivity.
"q34223624.txt" because question 34223624 contained this data
1.1.1.1
1.1.1.1
1.1.1.1
1.2.1.2
1.2.1.2
1.2.1.2
1.3.1.3
1.3.1.3
1.3.1.3
on which it works perfectly.
Did come across this issue and had to resolve it myself because the use was particulate to my need.
I needed to find duplicate URL's and order of lines was relevant so it needed to be preserved. The lines of text should not contain any double quotes, should not be very long and sorting cannot be used.
Thus I did this:
setlocal enabledelayedexpansion
type nul>unique.txt
for /F "tokens=*" %%i in (list.txt) do (
find "%%i" unique.txt 1>nul
if !errorlevel! NEQ 0 (
echo %%i>>unique.txt
)
)
Auxiliary: if the text does contain double quotes then the FIND needs to use a filtered set variable as described in this post: Escape double quotes in parameter
So instead of:
find "%%i" unique.txt 1>nul
it would be more like:
set test=%%i
set test=!test:"=""!
find "!test!" unique.txt 1>nul
Thus find will look like find """what""" file and %%i will be unchanged.
I have used a fake "array" to accomplish this
#echo off
:: filter out all duplicate ip addresses
REM you file would take place of %1
set file=%1%
if [%1]==[] goto :EOF
setlocal EnableDelayedExpansion
set size=0
set cond=false
set max=0
for /F %%a IN ('type %file%') do (
if [!size!]==[0] (
set cond=true
set /a size="size+1"
set arr[!size!]=%%a
) ELSE (
call :inner
if [!cond!]==[true] (
set /a size="size+1"
set arr[!size!]=%%a&& ECHO > NUL
)
)
)
break> %file%
:: destroys old output
for /L %%b in (1,1,!size!) do echo !arr[%%b]!>> %file%
endlocal
goto :eof
:inner
for /L %%b in (1,1,!size!) do (
if "%%a" neq "!arr[%%b]!" (set cond=true) ELSE (set cond=false&&goto :break)
)
:break
the use of the label for the inner loop is something specific to cmd.exe and is the only way I have been successful nesting for loops within each other. Basically this compares each new value that is being passed as a delimiter and if there is no match then the program will add the value into memory. When it is done it will destroy the target files contents and replace them with the unique strings
I've been trying to make a batch file that makes folders named after the people on a .txt file list, and then gives them full access to modifying their own personal folder.
The problem is that I keep getting a ' delims= " was unexpected at this time' error.
Here's my code here, I was wondering if you guys would be able to find out what I did wrong, thanks ^-^
(Btw I haven't added the permissions part yet, I just need to get this part sorted out first)
CODE: http://pastebin.com/XLi11nZa
NAMES LIST: http://pastebin.com/xbh3WTSv
#echo off
color A
echo What is the name of list file? (Do not include format)
SET /P list=
setlocal EnableDelayedExpansion
set "cmd=findstr /R /N "^^" %list%.txt | find /C ":""
for /f %%a in ('!cmd!') do set m=%%a
SET c=0
echo !m! folders to be created. Continue? (Y/N)
SET /P ANSWER=
if /i {%ANSWER%}=={y} (goto :yes)
if /i {%ANSWER%}=={yes} (goto :yes)
exit
:yes
echo Now creating %m% folders.....
for /f "eol=; tokens=1 delims=," %%i in ("%list%.txt") do (
SET /a c = !c! + 1
mkdir "%%i"
echo !c!/%m% folders created [%%i]
)
endlocal
echo Now adding permissions to %m% folders.....
pause
setlocal enabledelayedexpansion
SET c1=0
for /f "eol=; tokens=1 delims=," %%i in ("%list%.txt") do (
SET /a c1 = !c1! + 1
SET word=1
SET /a showme=c1-1
SET showme=skip=%showme%
IF !c1! equ 1 set "showme= "
FOR /F "tokens=%word% %showme% delims= " %%F IN ("%list%") DO if defined
showme set showme=%%F
SET first=%showme:~0,1%
SET word=2
SET /a showme1=c1-1
SET showme1=skip=%showme1%
IF %c1% equ 1 set "showme1= "
FOR /F "tokens=%word% %showme1% delims= " %%L IN ("%list%") DO if
defined showme1 set showme1=%%L
set B=%showme1%%first%
set _STRING=%B%
set "_UCASE=ABCDEFGHIJKLMNOPQRSTUVWXYZ"
set "_LCASE=abcdefghijklmnopqrstuvwxyz"
for /l %%a in (0,1,25) do (
call set "_FROM=%%_UCASE:~%%a,1%%
call set "_TO=%%_LCASE:~%%a,1%%
call set "_STRING=%%_STRING:!_FROM!=!_TO!%%
)
set _STRING
echo %_STRING%
echo %_STRING%>>testing.txt
endlocal
pause
)
names list
Loralee Stucky
Tomas Silberman
Marleen Rosell
Phyllis Steier
Elmo Jetter
Kristyn Spruell
Willetta Vandermeer
Hazel Alsobrook
Naida Nixon
Nadia Godfrey
Lavonna Antunez
Mac Castile
Tamela Stover
Piedad Heidrick
Hien Welsh
Carolin Gularte
Mariko Tolentino
Alia Graddy
Deadra Rehkop
Donella Pittman
Replace
for /f "eol=; tokens=1 delims=," %%i in ("%list%.txt") do (
by
for /f "usebackq eol=; tokens=1 delims=," %%i in ("%list%.txt") do (
twice.
Without the usebackq option, a double-quoted set of for /F is interpreted as a literal string rather than a file. Removing the double-quotes could work but could also lead to problems with files that have spaces in their names.
Another thing: you are dynamically creating the skip=# option for for /F, where # stands for a number. you have to make sure that this number is always positive, so 0 is not understood by for /F which could also lead to your error message.
So you could add an if check whether the number is greater than zero and do not add the skip option otherwise (by clearing your showme variables).
And last but not least: the delayed expansion is not always used properly: sometimes in the block startung at the for command in line #26 of your code and reaching to the end, you are not consistently using !! for expansion of variables showme, showme1 and c1, which are the ones that are modified within that code block.
The folders will get created proper if you remove the double quotes from the filename variable for /f "eol=; tokens=1 delims=," %%i in (%list%.txt) do ( change that line and you'll get past this part.
You may want to do the same in the permissions section.
Thanks for you time! This probably won't be a challenge for you.
So I have a list that is a txt file with the format ######.NAME-DATE which corresponds to files. The ##'s are unique identifying numbers, with the date representing different files for the same number. I want to have a batch file ask for the number and find all the files corresponding to that number and present this as a menu so the user can choose which she/he wants to open.
Here is what I have so far:
#echo off
set /p Input=Enter MRN:
set var=
setlocal enabledelayedexpansion
for /f "tokens=* delims=:" %%a in ('findstr "%Input%" log.txt') do (
set var=!var!%%a"|"
SET /A COUNT += 1
)
set var=!var!
endlocal
PAUSE
Any help would be greatly appreciated! Thank you!
#ECHO OFF
SETLOCAL
:: remove variables starting $
FOR /F "delims==" %%a In ('set $ 2^>Nul') DO SET "%%a="
set /p Input=Enter MRN:
for /f "tokens=1*delims=:" %%a in ('findstr /i /b /n /L "%Input%" q28574900.txt') do (
set "$%%a=%%b"
)
SET "selection="
for /f "tokens=1,2*delims==:" %%a in ('set $ 2^>nul^|findstr /n /r "^"') do (
ECHO %%a : %%c
SET /a selection=%%a
)
IF NOT DEFINED selection ECHO no matches&GOTO :eof
SET "selection="
SET /p "selection=Select which ? "
for /f "tokens=1,2*delims==:" %%a in ('set $ 2^>nul^|findstr /n /r "^"') do (
IF "%selection%"=="%%a" SET "selection=%%c"&GOTO run
)
ECHO invalid selection
GOTO :eof
:run
ECHO run whatever using %selection%
GOTO :EOF
I used a file named q28574900.txt containing some filename data for my testing. (woud have been better if you'd provided a sample)
First, select names according to input, but with the /b switch (to match at beginning of line) /L for literal-match /i for case-insensitive (in case you want alpha-match too) and /n to provide a unique number: at the start of the line. Having first cleared out all $ variables, set $uniquenumber to the filename found.
Display the menu by running all the values of set $ through a findstr /n /r. The lies would be of the form 3: $3=filename3 so delimit on : and = and show the first and third tokens. UUse selection as a flag (if set, 1 or more files found - can use the fact that if selection is 1 at the end to auto-run if desired)
Then ask for a selection and match the selection made to the list using the same method as used to display the menu. If you find the selection made, set the filename in selection and run the required program, if not, report the problem and finish.
Note that if you enter "12" as input then all files starting 12 will be displayed. If you want to match including the . then append . to %input% in the first findstr.
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
)
)