Batch: line & remove - batch-file

I want a batch file which: removes a certain line [line number by %lnum%] in a txt file.

That sounds like a job for sed. On windows, you'd have to install a windows port and then call sed from within your batch file.
sed '<linenumber>d' filename > newfilename
To delete the 4th line:
sed '4d' filename > newfilename

If you are in windows and you want to do it in a batch file, you could do the following by brute force:
#echo off
setlocal ENABLEDELAYEDEXPANSION
SET lineNum=
SET filename=%1
SET targetLine=%2
SET targetFile=%filename%.tmp
DEL %targetFile%
FOR /F " tokens=1 delims=" %%i in (%filename%) do (
SET /a lineNum += 1
if NOT !lineNum! == !targetLine! ECHO %%i >> !targetFile!
)
REN %filename% %filename%.orig
REN %targetFile% %filename%
You pass into the batch the name of your target file and the line number you want removed. It creates a temporary file, pipes the 'good' lines from your original into the temp and then finishes up by renaming the files so that you keep your original and have the modified file in place.

Pure cmd?:
delline.cmd number filename
#echo off
setlocal ENABLEDELAYEDEXPANSION
set line=%~1
set file=%~nx2
set dSource=%~dp2
set i=0
for /F "delims=" %%l in (%dSource%%file%) do (
set /a i+=1
if not !i! EQU %line% call :BuildFile "%%l"
)
del /f "%dSource%%file%" >nul
for %%l in (%_file%) do echo %%~l>>"%dSource%%file%"
endlocal& exit /b 0
:BuildFile
set _file=%_file% %1
exit /b 0
___Notes_____
1: No checks for parameters. First need be a number, the second a file or path+file.
2: As with other answers, no temporary file either.
3: Using setlocal would allow you to integrate this code easy within a script by naming it :delline and using it like: call :delline number file
WARNING: Any blank line from the source file would be skipped/lost in the reading process (by the for..loop). A file with, says 10 lines from which 4 are blanks, would be read as 6 lines to be processed. The line number given would be applied (thus, deleted) from the 6 data lines, and not the starting 10.
Edit
Went a bit too fast, did not see akf's answer which looks real close to mine.

don't have to use any external command. you can use vbscript
Set objFS = CreateObject("Scripting.FileSystemObject")
Set objArgs = WScript.Arguments
num = objArgs(0)
strFile = objArgs(1)
Set objFile = objFS.OpenTextFile(strFile)
Do Until objFile.AtEndOfLine
linenum = objFile.Line
If linenum = Int(num) Then
objFile.SkipLine
End If
strLine = objFile.ReadLine
WScript.Echo strLine
Loop
how to use:
C:\test>cscript /nologo removeline.vbs 4 file.txt > newfile.txt

Related

Changing a flag in the ini file from batch script

I have a script which will check if the file names and the content of the files are same or not, below is the code and it is working fine
ECHO OFF
CLS
for %%i in (C:\Users\f1ym41a\Documents\deep\*.DAT) do (
fc C:\Users\f1ym41a\Documents\deep\MOVE.DAT %%i > NUL
if errorlevel 1 (
CALL :error
echo C:\Users\f1ym41a\Documents\deep\MOVE.DAT and %%i are different >>output.log
) ELSE (
CALL :next
echo C:\Users\f1ym41a\Documents\deep\MOVE.DAT and %%i are same >>output.log
)
timeout 5
)
PAUSE
What i need to do is if the file names are same then it will change the flag in the ini file to 1. Below is the ini file (deep.ini)
[INI]
flag = 0
Since i am new to batch scripting. Can somebody help me out with this?
You can try with replacer.bat:
call replacer.bat move.dat "flag = 0" "flag = 1"
This is an easy to achieve task with using JREPL.BAT written by Dave Benham which is a batch file / JScript hybrid to run a regular expression replace on a file using JScript.
#echo off
if not exist "%USERPROFILE%\Documents\deep\MOVE.DAT" goto :EOF
if not exist "%~dp0jrepl.bat" goto :EOF
call "%~dp0jrepl.bat" "^(flag *= *)0" "$11" /F "%USERPROFILE%\Documents\deep\MOVE.DAT" /O -
The batch file first checks if the file to modify exists at all and immediately exits if this condition is not true, see Where does GOTO :EOF return to?
The batch file JREPL.BAT must be stored in same directory as the batch file with the code above. For that reason the batch file checks next if JREPL.BAT really exists in directory of the batch file and exits if this condition is not true.
The meaning of the regular expression search string is:
^ ... find at beginning of a line
(...) ... a string referenced in replace string with $1 to keep this part of found string unmodified
flag ... case-sensitive the string flag
 * ... with 0 or more spaces
= ... and an equal sign
 * ... and once more 0 or more spaces
0 ... and the character 0.
The replace string back-references the found string between beginning of line and character 0 with $1 and replaces 0 by 1.
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 also %~dp0 ... drive and path of argument 0 which is the batch file path always ending with a backslash.
echo /?
goto /?
if /?
jrepl.bat /?
:: 1st need remove some possible space in the string to got more precision
when compare them: "flag = 0" will became "flag=0", no
space and no tab.
:: 2nd for to do this, use this "' (2 characters) to set a variable that
use "=" to string instead a special character,
by set "'=flag=0" (very old technical!)
:: 3rd treat equal, treat tab character, and to remove it, because some time
this is a invisible and possible character that can eventually occur
in file dat, see in this question 10878138
:: 4th Compare the strings by string from file by file, line by line...
:: finely You need replace line in the file (.dat or .ini) this part I´m really confuse, but the code are above, sorry if my error!
Obs: use the conversion of this "flag = 0" this this one "flag=0", only for processing comparatives operation, wend the %%i match flag = 0 then only changed to replace to files by flag = 1, bat, a specific thing here is the command fc are comparing %%i, by the same file in looping for with no other file.
#echo off && setlocal EnableExtensions EnableDelayedExpansion
set "'=flag=0"
set _file_new_flag1="%temp%\Flag1.dat"
set _path_to_dats=C:\Users\f1ym41a\Documents\deep\
for /f "delims= " %%T in ('forFiles /p "." /m "%~nx0" /c "cmd /c echo(0x09"') do set "_tab=%%T"
type nul >output.log && set "_tab=%_tab:~0,1%"
cd /d "!_path_to_dats!"
for /f "tokens=* delims= " %%x in ('dir /o-d /on /b "*.dat"') do (
if defined _file_new_flag (
move /y "!_file_new_flag1!" "!_file_now!"
set _file_now=<nul
set "_file_now=%%~x"
) else (
set "_file_now=%%~x"
)
call :_file_compare_:
)
endlocal & goto :_end_of_file_:
:_file_compare_:
for /f "tokens=* delims= " %%X in ('type "!_file_now!"') do (
for /f "tokens=* delims= " %%i in ('echo/"%%~X"') do (
set "_to_compare=%%~i"
call set "_to_compare=!_to_compare: =!"
for /f "tokens=* delims=" %%I in ('echo/%_tab%') do call set "_to_compare=!_to_compare:%%I=!"
if ["!_to_compare!"] equ ["%'%"] (
echo/C:\Users\f1ym41a\Documents\deep\MOVE.DAT and %%i are same >>output.log
echo/%%~i>>!_file_new_flag1!
) else (
echo/C:\Users\f1ym41a\Documents\deep\MOVE.DAT and %%i are different >>output.log
echo/flag = 1>>!_file_new_flag1!
)
timeout /t 5
set _to_compare=<nul
)
)
exit /b
:_end_of_file_:
So sorry about my English.

How to read first line from a SQL file using standard windows command line

Is it possible to read just the first line from a .sql file in the windows command line?
If so, how can I do this - googleing has not come up with a solution that works.
All I have is standard windows command prompt
This looks like a copy of this question;
Windows batch command(s) to read first line from text file
Quoting the accepted answer from that ticket;
Here's a general-purpose batch file to print the top n lines from a file like the GNU head utility, instead of just a single line.
#echo off
if [%1] == [] goto usage
if [%2] == [] goto usage
call :print_head %1 %2
goto :eof
REM
REM print_head
REM Prints the first non-blank %1 lines in the file %2.
REM
:print_head
setlocal EnableDelayedExpansion
set /a counter=0
for /f ^"usebackq^ eol^=^
^ delims^=^" %%a in (%2) do (
if "!counter!"=="%1" goto :eof
echo %%a
set /a counter+=1
)
goto :eof
:usage
echo Usage: head.bat COUNT FILENAME
For example:
Z:\>head 1 "test file.c"
; this is line 1
Z:\>head 3 "test file.c"
; this is line 1
this is line 2
line 3 right here
It does not currently count blank lines. It is also subject to the batch-file line-length restriction of 8 KB.
To read just the first line of a (text) file:
<file.txt set /p line=
echo %line%
This is the easiest solution. Dependent on the content (poison chars), echo might fail.

Combining files and adding filename within combined file(or timestamp within filename)

I have a batch script which loops through a series of json files in a directory and combines them. It also adds a square bracket at the beginning and end of the combined file, and a comma between each file combined(to form a Json array).
#echo off
setlocal enableDelayedExpansion
dir /b /s /a-d C:\JSON_LOADER\Pre_Processing_Files\JSON_FILE*.json >files.temp
call :read <files.temp
del files.temp
del /q C:\JSON_LOADER\Pre_Processing_Files\JSON_FILE*.json
exit /b
:read
set "file="
set /p "file="
if not defined file exit /b
for /f "delims=/ tokens=1-3" %%a in ("%DATE:~4%") do (
for /f "delims=:. tokens=1-4" %%m in ("%TIME: =0%") do (
set /a cnt=%%c-%%b-%%a-%%m%%n%%o%%p
)
)
call :write >C:\JSON_LOADER\COMBINED\JSON_FILE-%date:~-4,4%%date:~-7,2%%date:~-10,2%-%cnt%.json
goto :read
:write
echo [
type "!file!"
echo(
for /l %%N in (2 1 10000) do (
set "file="
set /p "file="
if not defined file goto :end
echo ,
type "!file!"
echo(
)
:end
echo ]
exit /b
What I would like to do is also add the file name of each file at the end of each record in the combined file. The filename contains a timestamp that I require when loading the data into SQL. a sample filename would be;
JSON_FILE-20160816-104507.json
Ideally I would like the capture the '20160816-104507' timestamp section only, however I would be happy with just the full filename also, as I can process this filename in SQL. For the example above, I would like to add;
,"Filename":"JSON_FILE-20160816-104507.json"
A further complication is that each .json file that I am combining is contained within curly braces {} . I would require the filename that I am inserting to appear before the last curly brace } of each line. So for example, a sample of the current resulting combined file is;
[
{"object":"JSON_FILE","eventType":"CREATE","JsonId":12345}
,
{"object":"JSON_FILE","eventType":"CREATE","JsonId":123445}
,
{"object":"JSON_FILE","eventType":"CREATE","JsonId":123455}
]
I would like to append the filename information(or timestamp within the filename) to the end of each record, but within the curly brace like this example;
[
{"object":"JSON_FILE","eventType":"CREATE","JsonId":12345,"Filename":"JSON_FILE-20160816-104507.json"}
,
{"object":"JSON_FILE","eventType":"CREATE","JsonId":12345,"Filename":"JSON_FILE-20160816-104601.json"}
,
{"object":"JSON_FILE","eventType":"CREATE","JsonId":12345,"Filename":"JSON_FILE-20160816-104929.json"}
]
Another option, if it is a possibility, is to run the files before combining though F.A.R.T, replacing the final curly bracket with ,"Filename":"[filename]"} however I'm unsure of how to capture the file name in a recursive find and replace in the application.
Try this:
setlocal
:: Set options
set SourceFileFilter=JSON_FILE*.json
set resultFile=result.txt
::Process each file
echo [ > %resultFile%
set IsFirst=1
for %%i in (%SourceFileFilter%) do call :ProcessFile "%%i"
echo ] >> %resultFile%
endlocal & goto:eof
:ProcessFile
setlocal
:: THE FOLLOWING LINES ARE OPTIONAL, JUST TO GET TIMESTAMP (STORED IN LOCAL VARIABLE)
set Timestamp=%~1
set Timestamp=%Timestamp:JSON_FILE-=%
set Timestamp=%Timestamp:.json=%
echo The timestamp is stored in the local %%Timestamp%% variable: %Timestamp%
:: END OPTIONAL
:: Add "," if not the first processed file
if NOT "%IsFirst%"=="1" echo ,>> %resultFile%
set /p JsonFile=<%1
:: %JsonFile:}=% removes the } char
echo %JsonFile:}=%,"Filename":"%~1"}>> %resultFile%
:: End local environment, but before ending it, save IsFirst (as empty) for external usage, then exit
endlocal & set "IsFirst=" & goto:eof

Combining multiple text files with a limit per file

I have a batch script that will combine all .txt files with a few caveats, such as adding a comma in between each file and adding a square bracket at the start and end of the output file.
echo [ >> output.txt
for %f in (*.txt) do type "%f" >> output.txt & echo. >> output.txt & echo , >> output.txt
echo ] >> output.txt
What I would like to do it limit the output.txt to 10,000 txt files, whilst creating a new output.txt for the next 10,000 files. So for 25,000 records i will end up with;
Output1.txt (10,000 txt files)
Output2.txt (10,000 txt files)
Output3.txt (5,000 txt files)
How can I change my script to accommodate this?
Also if possible, I don't really want a comma at the end of the very last record that it combines. Is there a way to achieve this?
There are issues with your existing code:
A simple FOR loop will likely include your Output file(s). Obviously you don't want that. That could be prevented by writing the file list to a temp file, before any output is created. Easily done via DIR /B /A-D *.txt >tempFile
It takes significant time to repeatedly open the same output file thousands of times. Better (faster) to open it once, if possible.
Ideally, the final code should do most of the processing in some kind of FOR loop, with delayed expansion to enable working with changing values within the loop. Reading file names with a FOR loop can cause problems with delayed expansion because it will corrupt any name that happens to contain !. It takes a bit more code, but using SET /P to read the file is significantly faster, and delayed expansion doesn't cause problems.
Typically you must know the total number of lines in a file to detect the end when using SET /P. But in this case, the absence of data in a row indicates the end of file - There can never be any empty lines in DIR /B output.
The following code is untested, but if it does not work, then any fix should be minor.
#echo off
setlocal enableDelayedExpansion
dir /b /a-d *.txt >files.temp
set /a cnt=0
call :read <files.temp
del files.temp
exit /b
:read
set "file="
set /p "file="
if not defined file exit /b
set /a cnt+=1
call :write >output%cnt%.txt
goto :read
:write
echo [
type "!file!"
echo(
for /l %%N in (2 1 10000) do (
set "file="
set /p "file="
if not defined file goto :end
echo ,
type "!file!"
echo(
)
:end
echo ]
exit /b

Execute VBS from Batch on All Files in Directory

How can I loop the following batch code on all files in a directory:
for /f "tokens=*" %%f in ('dir /b *.txt') do (
set OldFile=%cd%/%%f
set NewFile=%cd%/2%%f
echo. > "%NewFile%"
start far.vbs "%NewFile%" "%OldFile%"
)
where the far.vbs is as follows:
Set OldFile = CreateObject("Scripting.FileSystemObject")
Set rdOldFile = OldFile.OpenTextFile(WScript.Arguments(1), 1)
oContent = rdOldFile.ReadAll
rdOldFile.Close
Set lOldFile = CreateObject("Scripting.FileSystemObject")
Set lrdOldFile = OldFile.OpenTextFile(WScript.Arguments(1), 1)
oLen = Len(lrdOldFile.ReadAll)
lrdOldFile.Close
oData = oContent
oData = Right(oContent, oLen-1)
oData = Left(oData, oLen-2)
Set NewFile = CreateObject("Scripting.FileSystemObject")
Set fData = NewFile.OpenTextFile(WScript.Arguments(0), 2)
fData.WriteLine (oData)
fData.Close
Currently no file is generating and the vbs code does not seem to execute. The directory should contain a text file with some generic string and the far.vbs script with remove the first and last two characters.
The Purpose of this script is to delete the portions of unnecessary characters from multiple files in a folder.
Variable expansion in a for loop doesn't work the way you expect. The entire loop is read as one statement, and all %var% are expanded at that point. To make your code work you need to enable delayed expansion. You may also want to use cscript.exe instead of start.
setlocal EnableDelayedExpansion
for /f "tokens=*" %%f in ('dir /b *.txt') do (
set "OldFile=%cd%/%%f"
set "NewFile=%cd%/2%%f"
echo. > "!NewFile!"
cscript.exe //NoLogo far.vbs "!NewFile!" "!OldFile!"
)

Resources