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.
Related
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
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 echo all directories which do not starts let's say with a letter. I write following snippet
#echo off
for /d %%g in (*) do (
echo %%~nxg
)
and it prints out all directories. How should I filter out those starts with a? I'm trying do something with IF-Statement, but fail miserably.
Output filtering
dir /ad /b | findstr /i /v /b "a"
List the directories (/ad) and pipe (|) the output of the command into findstr, that will select the lines that does not contain (/v) at the beginning (/b) the string "a", case insensitive (/i)
Substring
#echo off
setlocal enableextensions enabledelayedexpansion
for /d %%a in (*) do (
set "name=%%~na"
if /i not "!name:~0,1!"=="a" echo %%a
)
for replaceable parameters do not allow the use of substring operations, so a variable is needed. But as the variable is changed inside a block of code (code in parenthesis) and normal variable expansion is done when the block is parsed, not when it is executed, delayed expansion is needed to retrieve (read) the value from the changed variable.
The problem with this code is it will fail when folder's names contain ! as it will be consumed by the parser in the set command. To handle it, delayed expansion should be enabled/disabled when needed
#echo off
setlocal enableextensions disabledelayedexpansion
for /d %%a in (*) do (
set "name=%%~na"
setlocal enabledelayedexpansion
for %%b in ("!name:~0,1!") do (
endlocal
if /i not "%%~b"=="a" echo %%a
)
)
Character removal
#echo off
setlocal enableextensions disabledelayedexpansion
for /d %%a in (*) do (
for /f "tokens=* delims=aA" %%b in ("a%%a") do (
if /i "%%~b"=="%%~a" echo %%a
)
)
Here a for /f is used, configured to see the letters aA as delimiters but to retrieve all the tokens. This will make the for /f remove all the delimiters (aA) from the start of the line. If the remaining data is equal to the initial data, the name of the folder does not start with a or A
for /d %%g in (*) do (
for /f "eol=a tokens=* delims=" %%# in ("%%~nxg") do echo %%~fg
)
To do it with an IF, try this:
#ECHO OFF
SetLocal EnableDelayedExpansion
FOR /D %%g IN (*) DO (
SET tmp=%%~nxg
IF NOT "!tmp:~0,1!"=="a" (
ECHO %%~nxg
)
)
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 am trying to find a list of machines in files in folders, and print out the last line of the output only.
#echo off
for /f %%a in (computers.txt) do findstr /xs "%%a" unhealthy.txt
pause
The computers.txt file has a list of 300 machines.
I want that to output only the last line of each instance it finds.
Right now the command displays and outputs all instances of the computer name, not just the tail end. I've tried to use "tail for Windows" but am getting errors as well.
Current output:
2013\10-Oct\28\unhealthy.txt:WIN57505
2013\10-Oct\29\unhealthy.txt:WIN57505
2013\10-Oct\30\unhealthy.txt:WIN57505
2013\10-Oct\31\unhealthy.txt:WIN57505
2013\11-Nov\1\unhealthy.txt:WIN57505
2013\11-Nov\4\unhealthy.txt:WIN57505
2013\11-Nov\5\unhealthy.txt:WIN57505
2013\11-Nov\6\unhealthy.txt:WIN57505
I only want:
2013\11-Nov\6\unhealthy.txt:WIN57505
#echo off
setlocal enableextensions disabledelayedexpansion
for /f %%a in (computers.txt) do (
set "line="
for /f "tokens=*" %%b in ('findstr /xs "%%a" *') do set "line=%%b"
setlocal enabledelayedexpansion
echo(!line!
endlocal
)
pause
endlocal
setLocal enableDelayedExpansion
for /f %%a in (computers.txt) do for /f "tokens=*" %%A in ('findstr /xs "%%a"') do set lastFound=%%A
echo !lastFound!