Need to delete the first 5 lines and the last 2 lines of a txt file using a bat, been trying with a script that works on win 10 but not on win server 2012 r2.
Any idea why?
heres the script, i have
#echo off
setlocal EnableDelayedExpansion
set "FileToModify=getdoc.txt"
if not exist "%FileToModify%" goto:leavenow
set "TempFile=%TEMP%\FileUpdate.txt"
if exist "%TempFile%" del "%TempFile%"
if exist newFile.txt del newFile.txt
if exist Testfinal.txt del Testfinal.txt
if exist Test1.txt del Test1.txt
if exist myOriginalFile.txt del myOriginalFile.txt
set "Line=0"
for /F "useback delims=" %%L in ("%FileToModify%") do (
if !Line! GTR 4 (
echo %%L>>"%TempFile%"
) else (
set /A Line+=1
if !Line! GTR 4 echo %%L>>"%TempFile%"
)
)
copy /Y "%TempFile%" "%FileToModify%" >nul
set row=
for /F "delims=" %%j in (%FileToModify%) do (
if defined row echo.!row!>>Test1.txt
set row=%%j
)
set row=
for /F "delims=" %%j in (Test1.txt) do (
if defined row echo.!row!> Testfinal.txt
set row=%%j
)
echo { > newFile.txt
type %FileToModify% >> newFile.txt
type newFile.txt > getdoc.txt
del FileUpdate.txt
del newFile.txt
del Testfinal.txt
del Test1.txt
:leavenow
echo no file to clean!!!!
pause
exit
Ps- im sure there is a simple way to do this thanks
I suggest to use the following commented batch file for this task:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FileToModify=getdoc.txt"
if not exist "%FileToModify%" (
set "ErrorMessage=No file "%FileToModify%" to clean"
goto ErrorOutput
)
rem Get number of lines in file to modify by searching with FINDSTR for begin
rem of line which is true for every line in the file. Output by FINDSTR is the
rem line number a colon and the line itself for each line in file. For interest
rem is here just the line number left to first colon from last output line.
for /F "delims=:" %%I in ('%SystemRoot%\System32\findstr.exe /N /R "^" "%FileToModify%"') do set "LastLineNumber=%%I"
rem Has the file at least 8 lines to remove five lines at top and two
rem lines at bottom and have finally a file with at least one line?
if %LastLineNumber% LSS 8 (
set "ErrorMessage=File "%FileToModify%" has less than 8 lines"
goto ErrorOutput
)
rem Decrement the number of last line because the
rem last two lines should be removed from the file.
set /A LastLineNumber-=1
rem Derive name of temporary file to create in folder for temporary files
rem from name of file to modify by replacing its file extension by "tmp".
for %%I in ("%FileToModify%") do set "TempFile=%TEMP%\%%~nI.tmp"
rem Make sure the temporary file does not already exist from a previous
rem run of this batch file broke during processing by command interpreter.
del "%TempFile%" 2>nul
for /F "skip=5 tokens=1* delims=:" %%I in ('%SystemRoot%\System32\findstr.exe /N /R "^" "%FileToModify%"') do (
if %%I == %LastLineNumber% goto ReplaceFile
echo/%%J>>"%TempFile%"
)
:ReplaceFile
move /Y "%TempFile%" "%FileToModify%" 2>nul
if errorlevel 1 (
del "%TempFile%"
set "ErrorMessage=File "%FileToModify%" is write-protected"
goto ErrorOutput
)
endlocal
exit /B
:ErrorOutput
cls
echo %~f0
echo/
echo Error: %ErrorMessage%.
echo/
pause
Note: This batch file does not produce the right output for a file containing lines starting with 1 or more : because on second FOR option delims=: is used which results in splitting up such lines in line number output by FINDSTR assigned to loop variable I and everything after 1 or more colons assigned to loop variable J being the next character in ASCII table after specified loop variable I.
But this batch file handles files containing command line critical characters like &()[]{}^=;!'+,`~|<> well.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /? ... explains %~f0 (name of batch file with file extension and full path).
cls /?
del /?
echo /?
endlocal /?
exit /?
findstr /?
for /?
goto /?
if /?
move /?
pause /?
rem /?
set /?
setlocal /?
See DosTips forum topic ECHO. FAILS to give text or blank line - Instead use ECHO/ to understand why echo/ is used instead of echo. in batch file.
Related
The script I had been working on reads all folders on the CD-ROM drive "i" and searches for mp3 files, copying them onto the destination "e:\MP3\new".
#ECHO off
setlocal enabledelayedexpansion
cd /d "i:\"
set count=1
for /r %%d in (*.mp3) do (
set /a count+=1
)
echo There were %count% files found
set countb=1
for /r %%g in (*.mp3) do (
set /a countb+=1
echo|set /p = File: !countb!/%count%
copy "%%g" "e:\MP3\new" > nul
)
endlocal
Let´s suppose in this example that 115 files were found.
What I get from the above code:
There were 115 files found
File: 1/115 File: 2/115 File: 3/115 File: 4/115 File: 5/115 (...) File: 115/115
What I want:
There were 115 files found
File: X/115 where X will be constantly updated on the screen each time an mp3 file is successfully copied
Any help to fix that?
Firstly, you are initialising your counters wrongly, they should be set to zero (like set count=0) rather than one to get the correct numbers.
Secondly, you should replace echo|set /p = by < nul set /P =, because the pipe (|) is slower than simple (input) redirection (<) since it creates new cmd instances for either side.
To move the cursor in the Command Prompt window back to the beginning of the current line, you need to write the carriage-return character first. However, you cannot use this character as the first one with set /P, because it is going to be removed, together with other leading white-space characters. So you need another invisible character preceding the carriage-return that is not going to be removed; let us choose the back-space character.
Therefore, the fixed code may look like this, for instance:
#echo off
setlocal EnableDelayedExpansion
rem // Gather the back-space character:
for /F %%B in ('prompt $H ^& for %%Z in ^(.^) do rem') do set "BS=%%B"
rem // Gather the carriage-return character:
for /F %%C in ('copy /Z "%~f0" nul') do set "CR=%%C"
cd /D "I:\"
set /A "count=0"
for /R %%d in ("*.mp3") do (
set /A "count+=1"
)
echo There were %count% files found.
set /A "index=0"
for /R %%g in ("*.mp3") do (
set /A "index+=1"
< nul set /P ="%BS%!CR!File: !index!/%count%"
copy "%%~g" "E:\MP3\new\" > nul
)
endlocal
In below code i am tring to fetch the line no of string "AXX0000XXXA" from file data.txt,then fetching line by line and printing target.txt file,in between if the line reach the find line no i am adding one more line from file temp.txt.The code is working fine with the less nos of records(tested with 150 lines-File Size 100 kb),but when i am processing with 50K records(File Size 25MB) it is taking more then 25 minutes to process.could you please help me how i will process same in less time.
#echo off
setlocal enabledelayedexpansion
for /f "delims=:" %%a in ('findstr /n "AXX0000XXXA" "C:\Users\23456\Desktop\data.txt"') do (set find_line=%%a)
set /a counter=0
for /f "usebackq delims=" %%b in (`"findstr /n ^^ C:\Users\23456\Desktop\data.txt"`) do (
set curr_line=%%b
set /a counter=!counter!+1
if !counter! equ !find_line! (
type temp.txt >> target.txt
)
call :print_line curr_line
)
endlocal
:print_line
setlocal enabledelayedexpansion
set line=!%1!
set line=!line:*:=!
echo !line!>>target.txt
endlocal
Your code uses three Batch file constructs that are inherently slow: call command, >> append redirection and setlocal/endlocal, and these constructs are executed once per each file line! It would be faster to include the subroutine into the original code to avoid the call and setlocal commands, and an echo !line!>>target.txt command imply open the file, search for the end, append the data and close the file, so it is faster to use this construct: (for ...) > target.txt that just open the file once. An example of a code with such changes is in Compo's answer.
This is another method to solve this problem that may run faster when the search line is placed towards the beginning of the file:
#echo off
setlocal enabledelayedexpansion
for /f "delims=:" %%a in ('findstr /n "AXX0000XXXA" "C:\Users\23456\Desktop\data.txt"') do (set /A find_line=%%a-1)
call :processFile < "C:\Users\23456\Desktop\data.txt" > target.txt
goto :EOF
:processFile
rem Duplicate the first %find_line%-1 lines
for /L %%i in (1,1,%find_line%) do (
set /P "line="
echo !line!
)
rem Insert the additional line
type temp.txt
rem Copy the rest of lines
findstr ^^
exit /B
This should create target.txt with content matching data.txt except for an inserted line taken from tmp.txt immediately above the line matching the search string, AXX0000XXXA.
#Echo Off
Set "fSrc=C:\Users\23456\Desktop\data.txt"
Set "iSrc=temp.txt"
Set "sStr=AXX0000XXXA"
Set "fDst=target.txt"
Set "iStr="
Set/P "iStr="<"%iSrc%" 2>Nul
If Not Defined iStr Exit/B
Set "nStr="
For /F "Delims=:" %%A In ('FindStr/N "%sStr%" "%fSrc%" 2^>Nul') Do Set "nStr=%%A"
If Not Defined nStr Exit/B
( For /F "Tokens=1*Delims=:" %%A In ('FindStr/N "^" "%fSrc%"') Do (
If "%%A"=="%nStr%" Echo %iStr%
Echo %%B))>"%fDst%"
I have made it easy for you to change your variable data, you only need to alter lines 3-6.
I have assumed that this was your intention, your question was not clear, please accept my apologies if I have assumed incorrectly.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I have a text file. I have to swap odd and even lines.
I made a batch script that writes even lines into testfile2.txt and odd lines into testfile3.txt.
#echo off
setlocal EnableDelayedExpansion
set "filepath1=C:\\Users\\andyb\\Desktop\\testfile.txt"
set "filepath2=C:\\Users\\andyb\\Desktop\\testfile2.txt"
set "filepath3=C:\\Users\\andyb\\Desktop\\testfile3.txt"
set counter=0
set B=0
for /F %%A in (%filepath1%) do (
set /a B=!counter!%%2
if !B! equ 0 (echo %%A>>%filepath2%) else (echo %%A>>%filepath3%)
set /A counter=counter+1
)
And I want to take 1 line from file that contains odd lines, then 1 line from the file with even lines and write it to my first file. But I don't understand how to do it in FOR loop because it reads a line from only one file and I can't work with another file in this loop.
Example of input file:
1a
2b
3c
4d
Example of output file:
2b
1a
4d
3c
Try the following:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
rem // Define constants here:
set "_FILE=textfile.txt"
rem // Count number of lines:
for /F %%C in ('^< "!_FILE!" find /C /V ""') do set "COUNT=%%C"
rem // Divide by two, round up:
set /A "COUNT=(COUNT+1)/2"
< "!_FILE!" > "!_FILE!.tmp" (
rem // Read files in blocks of two lines:
for /L %%I in (1,1,%COUNT%) do (
set "LINE1=" & set "LINE2="
set /P LINE1=""
set /P LINE2=""
echo(!LINE2!
echo(!LINE1!
)
)
rem // Overwrite original file:
> nul move /Y "!_FILE!.tmp" "!_FILE!"
endlocal
exit /B
There are several solutions for this task.
The first one uses delayed expansion on execution of all lines of batch file exchanging odd and even lines. This means it does not work right for lines with an exclamation in line because ! is removed from line.
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "SourceFile=%USERPROFILE%\Desktop\TestFile.txt"
if not exist "%SourceFile%" goto EndBatch
set "TargetFile=%USERPROFILE%\Desktop\TestFile2.txt"
del "%TargetFile%" 2>nul
set "LineOdd="
for /F "usebackq delims=" %%I in ("%SourceFile%") do (
if not defined LineOdd (
set "LineOdd=%%I"
) else (
echo %%I>>"%TargetFile%"
echo !LineOdd!>>"%TargetFile%"
set "LineOdd="
)
)
if defined LineOdd echo !LineOdd!>>"%TargetFile%"
move /Y "%TargetFile%" "%SourceFile%"
:EndBatch
endlocal
Blank and empty lines are skipped by FOR and therefore missing in target file. And lines starting with a semicolon ; are ignored on reading each line by FOR and for that reason are missing also in output file. But those limitations should not matter here according to input example.
The limitations of first solution could be avoided using this batch code which is of course much slower:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceFile=%USERPROFILE%\Desktop\TestFile.txt"
if not exist "%SourceFile%" goto EndBatch
set "TargetFile=%USERPROFILE%\Desktop\TestFile2.txt"
del "%TargetFile%" 2>nul
set "LineOdd="
for /F "tokens=1* delims=:" %%H in ('%SystemRoot%\System32\findstr.exe /N /R "^" "%SourceFile%"') do (
if not defined LineOdd (
set "LineOdd=_%%I"
) else (
if "%%I" == "" (
echo/>>"%TargetFile%"
) else (
echo %%I>>"%TargetFile%"
)
setlocal EnableDelayedExpansion
if "!LineOdd!" == "_" (
echo/>>"%TargetFile%"
) else (
echo !LineOdd:~1!>>"%TargetFile%"
)
endlocal
set "LineOdd="
)
)
if defined LineOdd (
setlocal EnableDelayedExpansion
if "!LineOdd!" == "_" (
echo/>>"%TargetFile%"
) else (
echo !LineOdd:~1!>>"%TargetFile%"
)
endlocal
)
move /Y "%TargetFile%" "%SourceFile%"
:EndBatch
endlocal
It would be also possible to use hybrid batch file JREPL.BAT written by Dave Benham:
call jrepl.bat "^(.*)\r\n(.*)\r\n" "$2\r\n$1\r\n" /M /X /F "%USERPROFILE%\Desktop\TestFile.txt" /O "%USERPROFILE%\Desktop\TestFile2.txt"
move /Y "%USERPROFILE%\Desktop\TestFile2.txt" "%USERPROFILE%\Desktop\TestFile.txt"
The last line of the file must have a DOS/Windows line termination (carriage return \r and line-feed \n) if being an even line on using this solution.
For understanding the used commands/executables/batch files and how they work, open a command prompt window, execute there the following command lines, and read entirely all help pages displayed for each command/executable/batch file very carefully.
del /?
echo /?
endlocal /?
findstr.exe /?
for /?
goto /?
if /?
jrepl.bat /?
move /?
set /?
setlocal /?
Read also the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul and >>.
The following example will create two files from testfile.txt, file0.out containing the even lines, and file1.out containing the odd lines.
#Echo Off
SetLocal EnableDelayedExpansion
For /F "Tokens=1* Delims=:" %%A In ('FindStr/N "^" "testfile.txt"') Do (
Set/A "_=%%A%%2"
(Echo(%%B)>>file!_!.out)
Rename the output files according to your requirements.
I think to reinterleave the odd and even versions in reversed order isn't that difficult. Appending to Compo's try:
#Echo Off
SetLocal EnableDelayedExpansion
Set File=testfile
For /F "Tokens=1* Delims=:" %%A In ('FindStr/N "^" "%File%.txt"'
) Do Set/A "_=%%A%%2"&>>%File%_!_!.txt Echo(%%B
<%File%_0.txt (For /f "delims=" %%A in (%File%_1.txt) Do (
Set "B="&Set /P "B="
Echo(!B!
Echo(%%A
)) >%File%-new.txt
Del %File%_*
In case of an uneven total the second last line will be empty. sample Output:
2b
1a
4d
3c
5e
Hi I want to set value InFile for all text files in a directory which means that I want the batch file to load and do the command for all of the text files in the directory one by one.
Normally I just copy the command how many times files are then I replace Infile with every file name. By this code I get the file names and then I replace them.
cd /d "dir"
dir /a /b /-p /o:gen >names.txt
and here's the example of a command.
#Echo OFF
REM Set These Variables
SET "InFile=123.txt"
SET "OutFile=NowLoad.txt"
SET "Replace=KK"
SET "ReplaceWith=JJ"
REM Get Total Lines Number [including empty lines]
FOR /F %%A IN ('TYPE "%InFile%"^|find /v /c ""') DO SET "Till=%%A"
REM Create The OutFile with changes
SETLOCAL EnableDelayedExpansion
<"!InFile!" (
FOR /L %%a IN (1 1 0) DO SET /p "="
FOR /L %%A IN (1 1 %Till%) DO (
SET "line="
SET /P "line="
IF "!line!x" == "x" ( Echo.
) ELSE ( Echo !line:%Replace%=%ReplaceWith%!)
)
)>>"%OutFile%"
ENDLOCAL
no need to count the lines, just process every line:
setlocal enabledelayedexpansion
for %%f in (*.txt) do (
( for /f "delims=" %%A in (%%f) do (
set line=%%A
set line=!line:%Replace%=%ReplaceWith%!
echo(!line!
)
)>%%~nf.out
)
Note: the ( after echo handles empty lines (an empty line is written with no "echo is off" if !line! is empty)
edited to process all .txt files in the Folder. Because a fixed %oufile% would overwrite the same outfile with every processed infile, I changed it to a new Extension: <SameNameAsInputFile>.out
Another way...
Your script is DOIT.bat.
Change DOIT.bat to use a command line parameter for the filename you want to process.
#Echo OFF
REM Set These Variables
SET "InFile=%~1"
SET "OutFile=NowLoad.txt"
...
Create another file named CALLIT.bat
#ECHO OFF
FOR /F "usebackq tokens=*" %%f IN (`dir /b *.txt`) DO (
CALL DOIT.bat "%%~f"
)
Running CALLIT.bat will process every .txt file in the directory.
I need to move some files named in one text file to directories named in another different text file. Using Batch commands.
What I've tried.
#echo off
echo.
REM check if file is there
if exist K:\file_sync_diff\FileNameList.txt goto Label 1
REM display error
echo Can not find the File Name List
echo.
echo.
Pause
goto :eof
:Label 1
REM display that the file in the last check was found
echo found FileNameList.txt
REM check if file is there
if exist K:\file_sync_diff\FileDumpText.txt goto Label 2
REM display error
echo Can not find File Dump Text File
echo.
echo.
Pause
goto :eof
:Label 2
REM display that the file in the last check was found
echo found FileDumpText.txt
REM check if file is there
if exist K:\file_sync_diff\DirectoryNames.txt goto Label 3
REM display error
echo Can not find Directory Names Text File
echo.
echo.
Pause
goto :eof
:Label 3
REM display that the file in the last check was found
echo found DirectoryNames.txt
REM for loop to filter through every line in a file
echo.
for /f %%i in (K:\file_sync_diff\FileNameList.txt) do call :Sub %%i
goto Label 4
goto :eof
:Label 4
REM display message of the file being moved
echo.
echo Moving %1
REM copy the file just made to a directory with a name supplied in a text file
for /f %%i in (K:\file_sync_diff\DirectoryNames.txt) do call :Sub 2 %%i
echo.
goto :eof
:Sub
echo Writing %1
REM copy the contents of FileDumpText.txt to the file that was passed in the last method
type K:\file_sync_diff\FileDumpText.txt >> %1.txt
goto :eof
:Sub 2
REM moves the file to the directory supplied by label 4.
move /y %1.txt %1
echo.
goto :eof
Contents of FileNameList.txt
red
orange
purple
Contents of DirectoryNames.txt
K:\file_sync_diff\cat
K:\file_sync_diff\dog
K:\file_sync_diff\333
Not that it matters but the contents of FileDumpText.txt
Test text to be passed to the file
more text 1
more text 2
more text 3
The directories do exist in the K:\file_sync_diff folder.
Thank you for your help.
The end result should be the following
directory cat with red.txt inside with all of the contents of FileDumpText.txt inside it
directory dog with orange.txt inside with all of the contents of FileDumpText.txt inside it
directory 333 with purple.txt inside with all of the contents of FileDumpText.txt inside it
my suggestion with associative arrays:
#ECHO OFF &SETLOCAL
set "tfileA=K:\file_sync_diff\FileNameList.txt"
set "tfileB=K:\file_sync_diff\DirectoryNames.txt"
set "tfileC=K:\file_sync_diff\FileDumpText.txt"
for /f "tokens=1*delims=:" %%a in ('findstr /n $ "%tfileA%"') do set "$a%%a=%%b"&set /a countA=%%a
for /f "tokens=1*delims=:" %%a in ('findstr /n $ "%tfileB%"') do set "$b%%a=%%b"&set /a countB=%%a
for /f "tokens=1*delims=:" %%a in ('findstr /n $ "%tfileC%"') do set "$c%%a=%%b"&set /a countC=%%a
if "%countA%"=="%countB%" (echo %countA% line(s^) found in %tfileA% and %tfileB%.) else echo Line mismatch: %tfileA%:%countA% - %tfileB%:%countB%&goto:eof
if "%countA%"=="%countC%" (echo %countA% line(s^) found in %tfileC%.) else echo Line mismatch: %tfileA%:%countA% - %tfileC%:%countC%&goto:eof
SETLOCAL ENABLEDELAYEDEXPANSION
for /l %%a in (1 1 %countA%) do (
echo copy "!$a%%a!" "!$b%%a!"
echo ^>"!$b%%a!\!$a%%a!" echo(!$c%%a!
)
endlocal
output is:
3 line(s) found in K:\file_sync_diff\FileNameList.txt and K:\file_sync_diff\DirectoryNames.txt.
3 line(s) found in K:\file_sync_diff\FileDumpText.txt.
copy "red" "K:\file_sync_diff\cat"
>"K:\file_sync_diff\cat\red" echo(more text 1
copy "orange" "K:\file_sync_diff\dog"
>"K:\file_sync_diff\dog\orange" echo(more text 2
copy "purple" "K:\file_sync_diff\333"
>"K:\file_sync_diff\333\purple" echo(more text 3
I was successful using the following code, but with one issue. I get a ".txt" file now. This is caused by a return charter in the FileNameList.txt file but if their is no return after the last file name in the FileNameList.txt then that file doesn't get copied.
So I just need a line of code to delete ".txt" and not any other file with an actual name.txt Any help with that would be nice.
My current Code
#echo off
echo.
REM check if file is there
if exist F:\file_sync_diff\FileNameList.txt goto Label 1
REM display error
echo Can not find the File Name List
echo.
echo.
Pause
goto :eof
:Label 1
REM display that the file in the last check was found
echo found FileNameList.txt
REM check if file is there
if exist F:\file_sync_diff\FileDumpText.txt goto Label 2
REM display error
echo Can not find File Dump Text File
echo.
echo.
Pause
goto :eof
:Label 2
REM display that the file in the last check was found
echo found FileDumpText.txt
REM check if file is there
if exist F:\file_sync_diff\DirectoryNames.txt goto Label 3
REM display error
echo Can not find Directory Names Text File
echo.
echo.
Pause
goto :eof
:Label 3
REM display that the file in the last check was found
echo found DirectoryNames.txt
REM for loop to filter through every line in a file
echo.
for /f %%i in (F:\file_sync_diff\FileNameList.txt) do call :Sub %%i
goto Label 4
goto :eof
:Label 4
REM thanks to Endoro#StackOverFlow
#ECHO OFF &SETLOCAL
REM set associative arrays
set "tfileA=F:\file_sync_diff\FileNameList.txt"
set "tfileB=F:\file_sync_diff\DirectoryNames.txt"
REM setup for loops
for /f "tokens=1*delims=:" %%a in ('findstr /n $ "%tfileA%"') do set "$a%%a=%%b"&set /a countA=%%a
for /f "tokens=1*delims=:" %%a in ('findstr /n $ "%tfileB%"') do set "$b%%a=%%b"&set /a countB=%%a
SETLOCAL ENABLEDELAYEDEXPANSION
for /l %%a in (1 1 %countA%) do (
echo.
move "!$a%%a!.txt" "!$b%%a!"
echo.
echo ^>"!$b%%a!\!$a%%a!" echo(!$c%%a!)
echo.
endlocal
:Sub
echo Writing %1
REM copy the contents of FileDumpText.txt to the file that was passed in the last method
type F:\file_sync_diff\FileDumpText.txt >> %1.txt
goto :eof