I have written a windows batch code to rename the folders and files recursively from V34 to 35 and so on..and but I need to change same V34 to 35 inside a text file,which is residing inside the files
Folder---file--text file(Inside the text file need to change the V34 content to V35)
Please find the below code which I have written and let me know for the changes
#echo off
setlocal disableDelayedExpansion
set "old=V34"
set "new=V35"
for /f "delims=" %%F in ('dir /b /s *. *.xslt ^| sort /r') do (
set "source=%%F"
set "oldname=%%~nxF"
setlocal enableDelayedExpansion
set "newname=!oldname:%old%=%new%!"
if /i "!newname!" neq "!oldname!" (
echo ren "!source!" "!newname!"
ren "!source!" "!newname!"
) )
for /f "delims=" %%i in (.*) do (
set "source=%%i"
setlocal enabledelayedexpansion
set "newname=!oldname:%old%=%new%!"
echo ren "!source!" "!newname!"
ren "!source!" "!newname!"
endlocal
)
endlocal
simple solution use powershell for get all folder and file names then rename to new name see this example
get-childitem -filter *v34.txt | foreach { (Get-Content drive:\$_ ) | ForEach-Object { $_ -replace "v34", "v35" } | Set-Content v35.txt
for cmd you can get-content and then replace v34 to v35
type v34.txt|repl "v34" "v35" >v35.txt
for change content of txt file you can use fnrtooland down is example for you but still i suggest to you use powershell
for your code
.\fnr.exe --cl --dir "c:\" --filemask "*.txt" --find "v34" --replace "v35" --includeSubDirectories
your code :
#echo off
setlocal disableDelayedExpansion
set "old=V34"
set "new=V35"
for /f "delims=" %%F in ('dir /b /s *. *.xslt ^| sort /r') do (
set "source=%%F"
set "oldname=%%~nxF"
setlocal enableDelayedExpansion
set "newname=!oldname:%old%=%new%!"
if /i "!newname!" neq "!oldname!" (
echo ren "!source!" "!newname!"
ren "!source!" "!newname!"
) )
for /f "delims=" %%i in (.*) do (
set "source=%%i"
setlocal enabledelayedexpansion
set "newname=!oldname:%old%=%new%!"
echo ren "!source!" "!newname!"
ren "!source!" "!newname!"
endlocal
)
endlocal
complete code :
#echo off
setlocal disableDelayedExpansion
set "old=V34"
set "new=V35"
for /f "delims=" %%F in ('dir /b /s *. *.xslt ^| sort /r') do (
set "source=%%F"
set "oldname=%%~nxF"
setlocal enableDelayedExpansion
set "newname=!oldname:%old%=%new%!"
if /i "!newname!" neq "!oldname!" (
echo ren "!source!" "!newname!"
ren "!source!" "!newname!"
) )
c:\path\fnr.exe --cl --dir "c:\" --filemask "*.txt" --find "v34" --replace "v35" --includeSubDirectories
endlocal
batfile for replace with regex :
#if (#X)==(#Y) #end /* find string and replace
::************ Documentation ***********
::REPL.BAT version 6.2
:::
:::REPL Search Replace [Options [SourceVar]]
:::REPL /?[REGEX|REPLACE]
:::REPL /V
:::
::: Performs a global regular expression search and replace operation on
::: each line of input from stdin and prints the result to stdout.
:::
::: Each parameter may be optionally enclosed by double quotes. The double
::: quotes are not considered part of the argument. The quotes are required
::: if the parameter contains a batch token delimiter like space, tab, comma,
::: semicolon. The quotes should also be used if the argument contains a
::: batch special character like &, |, etc. so that the special character
::: does not need to be escaped with ^.
:::
::: If called with a single argument of /?, then prints help documentation
::: to stdout. If a single argument of /?REGEX, then opens up Microsoft's
::: JScript regular expression documentation within your browser. If a single
::: argument of /?REPLACE, then opens up Microsoft's JScript REPLACE
::: documentation within your browser.
:::
::: If called with a single argument of /V, case insensitive, then prints
::: the version of REPL.BAT.
:::
::: Search - By default, this is a case sensitive JScript (ECMA) regular
::: expression expressed as a string.
:::
::: JScript regex syntax documentation is available at
::: http://msdn.microsoft.com/en-us/library/ae5bf541(v=vs.80).aspx
:::
::: Replace - By default, this is the string to be used as a replacement for
::: each found search expression. Full support is provided for
::: substituion patterns available to the JScript replace method.
:::
::: For example, $& represents the portion of the source that matched
::: the entire search pattern, $1 represents the first captured
::: submatch, $2 the second captured submatch, etc. A $ literal
::: can be escaped as $$.
:::
::: An empty replacement string must be represented as "".
:::
::: Replace substitution pattern syntax is fully documented at
::: http://msdn.microsoft.com/en-US/library/efy6s3e6(v=vs.80).aspx
:::
::: Options - An optional string of characters used to alter the behavior
::: of REPL. The option characters are case insensitive, and may
::: appear in any order.
:::
::: A - Only print altered lines. Unaltered lines are discarded.
::: If the S options is present, then prints the result only if
::: there was a change anywhere in the string. The A option is
::: incompatible with the M option unless the S option is present.
:::
::: B - The Search must match the beginning of a line.
::: Mostly used with literal searches.
:::
::: E - The Search must match the end of a line.
::: Mostly used with literal searches.
:::
::: I - Makes the search case-insensitive.
:::
::: J - The Replace argument represents a JScript expression.
::: The expression may access an array like arguments object
::: named $. However, $ is not a true array object.
:::
::: The $.length property contains the total number of arguments
::: available. The $.length value is equal to n+3, where n is the
::: number of capturing left parentheses within the Search string.
:::
::: $[0] is the substring that matched the Search,
::: $[1] through $[n] are the captured submatch strings,
::: $[n+1] is the offset where the match occurred, and
::: $[n+2] is the original source string.
:::
::: Arguments $[0] through $[10] may be abbreviated as
::: $1 through $10. Argument $[11] and above must use the square
::: bracket notation.
:::
::: L - The Search is treated as a string literal instead of a
::: regular expression. Also, all $ found in the Replace string
::: are treated as $ literals.
:::
::: M - Multi-line mode. The entire contents of stdin is read and
::: processed in one pass instead of line by line, thus enabling
::: search for \n. This also enables preservation of the original
::: line terminators. If the M option is not present, then every
::: printed line is terminated with carriage return and line feed.
::: The M option is incompatible with the A option unless the S
::: option is also present.
:::
::: Note: If working with binary data containing NULL bytes,
::: then the M option must be used.
:::
::: S - The source is read from an environment variable instead of
::: from stdin. The name of the source environment variable is
::: specified in the next argument after the option string. Without
::: the M option, ^ anchors the beginning of the string, and $ the
::: end of the string. With the M option, ^ anchors the beginning
::: of a line, and $ the end of a line.
:::
::: V - Search and Replace represent the name of environment
::: variables that contain the respective values. An undefined
::: variable is treated as an empty string.
:::
::: X - Enables extended substitution pattern syntax with support
::: for the following escape sequences within the Replace string:
:::
::: \\ - Backslash
::: \b - Backspace
::: \f - Formfeed
::: \n - Newline
::: \q - Quote
::: \r - Carriage Return
::: \t - Horizontal Tab
::: \v - Vertical Tab
::: \xnn - Extended ASCII byte code expressed as 2 hex digits
::: \unnnn - Unicode character expressed as 4 hex digits
:::
::: Also enables the \q escape sequence for the Search string.
::: The other escape sequences are already standard for a regular
::: expression Search string.
:::
::: Also modifies the behavior of \xnn in the Search string to work
::: properly with extended ASCII byte codes.
:::
::: Extended escape sequences are supported even when the L option
::: is used. Both Search and Replace support all of the extended
::: escape sequences if both the X and L opions are combined.
:::
::: Return Codes: 0 = At least one change was made
::: or the /? or /V option was used
:::
::: 1 = No change was made
:::
::: 2 = Invalid call syntax or incompatible options
:::
::: 3 = JScript runtime error, typically due to invalid regex
:::
::: REPL.BAT was written by Dave Benham, with assistance from DosTips user Aacini
::: to get \xnn to work properly with extended ASCII byte codes. Also assistance
::: from DosTips user penpen diagnosing issues reading NULL bytes, along with a
::: workaround. REPL.BAT was originally posted at:
::: http://www.dostips.com/forum/viewtopic.php?f=3&t=3855
:::
::************ Batch portion ***********
#echo off
if .%2 equ . (
if "%~1" equ "/?" (
<"%~f0" cscript //E:JScript //nologo "%~f0" "^:::" "" a
exit /b 0
) else if /i "%~1" equ "/?regex" (
explorer "http://msdn.microsoft.com/en-us/library/ae5bf541(v=vs.80).aspx"
exit /b 0
) else if /i "%~1" equ "/?replace" (
explorer "http://msdn.microsoft.com/en-US/library/efy6s3e6(v=vs.80).aspx"
exit /b 0
) else if /i "%~1" equ "/V" (
<"%~f0" cscript //E:JScript //nologo "%~f0" "^::(REPL\.BAT version)" "$1" a
exit /b 0
) else (
call :err "Insufficient arguments"
exit /b 2
)
)
echo(%~3|findstr /i "[^SMILEBVXAJ]" >nul && (
call :err "Invalid option(s)"
exit /b 2
)
echo(%~3|findstr /i "M"|findstr /i "A"|findstr /vi "S" >nul && (
call :err "Incompatible options"
exit /b 2
)
cscript //E:JScript //nologo "%~f0" %*
exit /b %errorlevel%
:err
>&2 echo ERROR: %~1. Use REPL /? to get help.
exit /b
************* JScript portion **********/
var rtn=1;
try {
var env=WScript.CreateObject("WScript.Shell").Environment("Process");
var args=WScript.Arguments;
var search=args.Item(0);
var replace=args.Item(1);
var options="g";
if (args.length>2) options+=args.Item(2).toLowerCase();
var multi=(options.indexOf("m")>=0);
var alterations=(options.indexOf("a")>=0);
if (alterations) options=options.replace(/a/g,"");
var srcVar=(options.indexOf("s")>=0);
if (srcVar) options=options.replace(/s/g,"");
var jexpr=(options.indexOf("j")>=0);
if (jexpr) options=options.replace(/j/g,"");
if (options.indexOf("v")>=0) {
options=options.replace(/v/g,"");
search=env(search);
replace=env(replace);
}
if (options.indexOf("x")>=0) {
options=options.replace(/x/g,"");
if (!jexpr) {
replace=replace.replace(/\\\\/g,"\\B");
replace=replace.replace(/\\q/g,"\"");
replace=replace.replace(/\\x80/g,"\\u20AC");
replace=replace.replace(/\\x82/g,"\\u201A");
replace=replace.replace(/\\x83/g,"\\u0192");
replace=replace.replace(/\\x84/g,"\\u201E");
replace=replace.replace(/\\x85/g,"\\u2026");
replace=replace.replace(/\\x86/g,"\\u2020");
replace=replace.replace(/\\x87/g,"\\u2021");
replace=replace.replace(/\\x88/g,"\\u02C6");
replace=replace.replace(/\\x89/g,"\\u2030");
replace=replace.replace(/\\x8[aA]/g,"\\u0160");
replace=replace.replace(/\\x8[bB]/g,"\\u2039");
replace=replace.replace(/\\x8[cC]/g,"\\u0152");
replace=replace.replace(/\\x8[eE]/g,"\\u017D");
replace=replace.replace(/\\x91/g,"\\u2018");
replace=replace.replace(/\\x92/g,"\\u2019");
replace=replace.replace(/\\x93/g,"\\u201C");
replace=replace.replace(/\\x94/g,"\\u201D");
replace=replace.replace(/\\x95/g,"\\u2022");
replace=replace.replace(/\\x96/g,"\\u2013");
replace=replace.replace(/\\x97/g,"\\u2014");
replace=replace.replace(/\\x98/g,"\\u02DC");
replace=replace.replace(/\\x99/g,"\\u2122");
replace=replace.replace(/\\x9[aA]/g,"\\u0161");
replace=replace.replace(/\\x9[bB]/g,"\\u203A");
replace=replace.replace(/\\x9[cC]/g,"\\u0153");
replace=replace.replace(/\\x9[dD]/g,"\\u009D");
replace=replace.replace(/\\x9[eE]/g,"\\u017E");
replace=replace.replace(/\\x9[fF]/g,"\\u0178");
replace=replace.replace(/\\b/g,"\b");
replace=replace.replace(/\\f/g,"\f");
replace=replace.replace(/\\n/g,"\n");
replace=replace.replace(/\\r/g,"\r");
replace=replace.replace(/\\t/g,"\t");
replace=replace.replace(/\\v/g,"\v");
replace=replace.replace(/\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4}/g,
function($0,$1,$2){
return String.fromCharCode(parseInt("0x"+$0.substring(2)));
}
);
replace=replace.replace(/\\B/g,"\\");
}
search=search.replace(/\\\\/g,"\\B");
search=search.replace(/\\q/g,"\"");
search=search.replace(/\\x80/g,"\\u20AC");
search=search.replace(/\\x82/g,"\\u201A");
search=search.replace(/\\x83/g,"\\u0192");
search=search.replace(/\\x84/g,"\\u201E");
search=search.replace(/\\x85/g,"\\u2026");
search=search.replace(/\\x86/g,"\\u2020");
search=search.replace(/\\x87/g,"\\u2021");
search=search.replace(/\\x88/g,"\\u02C6");
search=search.replace(/\\x89/g,"\\u2030");
search=search.replace(/\\x8[aA]/g,"\\u0160");
search=search.replace(/\\x8[bB]/g,"\\u2039");
search=search.replace(/\\x8[cC]/g,"\\u0152");
search=search.replace(/\\x8[eE]/g,"\\u017D");
search=search.replace(/\\x91/g,"\\u2018");
search=search.replace(/\\x92/g,"\\u2019");
search=search.replace(/\\x93/g,"\\u201C");
search=search.replace(/\\x94/g,"\\u201D");
search=search.replace(/\\x95/g,"\\u2022");
search=search.replace(/\\x96/g,"\\u2013");
search=search.replace(/\\x97/g,"\\u2014");
search=search.replace(/\\x98/g,"\\u02DC");
search=search.replace(/\\x99/g,"\\u2122");
search=search.replace(/\\x9[aA]/g,"\\u0161");
search=search.replace(/\\x9[bB]/g,"\\u203A");
search=search.replace(/\\x9[cC]/g,"\\u0153");
search=search.replace(/\\x9[dD]/g,"\\u009D");
search=search.replace(/\\x9[eE]/g,"\\u017E");
search=search.replace(/\\x9[fF]/g,"\\u0178");
if (options.indexOf("l")>=0) {
search=search.replace(/\\b/g,"\b");
search=search.replace(/\\f/g,"\f");
search=search.replace(/\\n/g,"\n");
search=search.replace(/\\r/g,"\r");
search=search.replace(/\\t/g,"\t");
search=search.replace(/\\v/g,"\v");
search=search.replace(/\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4}/g,
function($0,$1,$2){
return String.fromCharCode(parseInt("0x"+$0.substring(2)));
}
);
search=search.replace(/\\B/g,"\\");
} else search=search.replace(/\\B/g,"\\\\");
}
if (options.indexOf("l")>=0) {
options=options.replace(/l/g,"");
search=search.replace(/([.^$*+?()[{\\|])/g,"\\$1");
if (!jexpr) replace=replace.replace(/\$/g,"$$$$");
}
if (options.indexOf("b")>=0) {
options=options.replace(/b/g,"");
search="^"+search
}
if (options.indexOf("e")>=0) {
options=options.replace(/e/g,"");
search=search+"$"
}
var search=new RegExp(search,options);
var str1, str2;
if (srcVar) {
str1=env(args.Item(3));
str2=str1.replace(search,jexpr?replFunc:replace);
if (!alterations || str1!=str2) if (multi) {
WScript.Stdout.Write(str2);
} else {
WScript.Stdout.WriteLine(str2);
}
if (str1!=str2) rtn=0;
} else if (multi){
var buf=1024;
str1="";
while (!WScript.StdIn.AtEndOfStream) {
str1+=WScript.StdIn.Read(buf);
buf*=2
}
str2=str1.replace(search,jexpr?replFunc:replace);
WScript.Stdout.Write(str2);
if (str1!=str2) rtn=0;
} else {
while (!WScript.StdIn.AtEndOfStream) {
str1=WScript.StdIn.ReadLine();
str2=str1.replace(search,jexpr?replFunc:replace);
if (!alterations || str1!=str2) WScript.Stdout.WriteLine(str2);
if (str1!=str2) rtn=0;
}
}
} catch(e) {
WScript.Stderr.WriteLine("JScript runtime error: "+e.message);
rtn=3;
}
WScript.Quit(rtn);
function replFunc($0, $1, $2, $3, $4, $5, $6, $7, $8, $9, $10) {
var $=arguments;
return(eval(replace));
}
example :
for /f %g in ( 'dir /a/b /s s:\' ) do type %g | findstr "v34" | repel.bat "v34" "v35"
resource for repel.bat link
Related
I want create a batch to replace spaces with a + sign if the space is in between quotes. Then I want to remove the quotes from a text file. How can I accomplish this?
So I want to change a line like this:
2016-01-11 14:45:09 Server 127.0.0.1 GET /global/images/logo_small.jpg - 80 - 173.252.120.117 "facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)" "-" www.vietnam.ttu.edu 200 200 200 1868 0
To this line.
2016-01-11 14:45:09 Server 127.0.0.1 GET /global/images/logo_small.jpg - 80 - 173.252.120.117 facebookexternalhit/1.1+(+http://www.facebook.com/externalhit_uatext.php) - www.vietnam.ttu.edu 200 200 200 1868 0
Thanks
You could use JREPL.BAT to arrive at a very concise and efficient solution. JREPL is a pure script based (JScript/batch) regular expression text processing utility that runs on any version of Windows from XP onward.
jrepl "\q| " "q=!q;''|q?'+':' '" /j /x /t "|" /jbegln "q=false" /f test.txt /o -
For this solution I use the /T option, which is very similar to the unix tr utility, or the sed y command.
I define two search terms, the first for a quote (The \X option enables the \q escape sequence), and the second for a space.
The /J option treats replacement strings as JScript. The first replacement string for the quote toggles a "q" variable TRUE or FALSE, and replaces the quote with an empty string. The second replacement string conditionally replaces the space with a plus or space, depending on the state of the "q" variable.
The /JBEGLN option initializes the "q" variable to FALSE at the beginning of each line.
The /F option specifies the input file, and the /O - option specifies that the output overwrites the original file.
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "filename1=%sourcedir%\q34732271.txt"
FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO ECHO %%a&SET "line="&CALL :process %%a
GOTO :EOF
:process
SET "addition=%~1"
IF not DEFINED addition ECHO %line:~1%&GOTO :eof
IF "%~1"==%1 (
REM quoted
SET "line=%line% %addition: =+%"
) ELSE (
SET "line=%line% %addition%"
)
shift
GOTO process
You would need to change the setting of sourcedir to suit your circumstances.
I used a file named q34732271.txt containing your data for my testing.
The echo %%a shows your one line of data on the screen and the echo within the :process routine shows that line processed.
Batch is not an ideal language to process strings as it exhibits sensitivity to many symbols. This process should work provided you are happy to have space-strings compressed and the source string does not contain , ;,tab % or any other symbol that cmd treats specially.
Here is a pure batch-file solution that walks through the characters in each line in file line.txt, replaces all SPACEs in between a pair of quotation marks "" by + signs and stores the result in text_new.txt. The input string may contain any characters, even special ones:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Define global constants here:
set "INFILE=line.txt"
set "OUTFILE=line_new.txt"
set "SEARCH= "
set "REPLACE=+"
set "KEEPQUOTES="
set "QUOTE="""
set "QUOTE=%QUOTE:~,1%"
set "QFLAG="
> "%OUTFILE%" (
for /F usebackq^ delims^=^ eol^= %%L in ("%INFILE%") do (
set "LINE=%%L"
call :SUB LINE
)
)
endlocal
exit /B
:SUB
setlocal EnableDelayedExpansion
set "LINE=!%1!"
set "LINENEW="
set /A "POS=0"
:LOOP
set "CHAR=!LINE:~%POS%,1!"
set /A "POS+=1"
if not defined CHAR (
echo(!LINENEW!
endlocal
exit /B
)
if "!CHAR!"=="!QUOTE!" (
if defined QFLAG (
set "QFLAG="
) else (
set "QFLAG=Quoted"
)
if defined KEEPQUOTES (
set "LINENEW=!LINENEW!!CHAR!"
)
) else if defined QFLAG (
if "!CHAR!"=="!SEARCH!" (
set "LINENEW=!LINENEW!!REPLACE!"
) else (
set "LINENEW=!LINENEW!!CHAR!"
)
) else (
set "LINENEW=!LINENEW!!CHAR!"
)
goto :LOOP
I have a comma-delimited text file with three fields. The first always containd a string, but the second, third, or both can be empty. When all contain strings, when only the third is emppty, and when the second and third are both empty, I get the expected result when it is read using the FOR command, the expected result being that the variables read from fields containing strings are equal to those strings, and the variables read from empty fields have null values. However, when the second fielkd is empty, and the third field contains a string, I get the unexpected result that the second variable, the one that was supposed to be read from the second field equals the contents of the third field, and the third variable has a null value.
How can I work around this problem?
This information is copied verbatim from my DosTips post: Safely parse nearly any CSV with parseCSV.bat
It is fairly common that someone wants to parse CSV using FOR /F. This is a simple task if you know all columns are populated, and there are no commas, newlines, or quotes within values. Assume there are 4 columns:
#echo off
for /f "tokens=1-4 delims=," %%A in (test.csv) do (
echo ----------------------
echo A=%%~A
echo B=%%~B
echo C=%%~C
echo D=%%~D
echo(
)
But things become more difficult if any of the following conditions occur:
1) Values may be empty, with consecutive commas. FOR /F treats consecutive delimiters as one, so it will throw off the column assignment.
2) Quoted values may contain commas. FOR /F will incorrectly treat a quoted comma as a column delimiter.
3) Quoted values may contain newlines. FOR /F will break the line at the newline and incorrectly treat the one row as two.
4) Quoted values may contain paired quotes that represent one quote. For example, "He said, ""Hello there"". A method is needed to convert "" into ".
Then there is a secondary problems that can crop up if delayed expansion is enabled.
5) A FOR variable %%A will be corrupted if it contains ! (or sometimes ^) if delayed expansion is enabled when the variable is expanded.
There are fairly easy solutions for some of these issues, but solving all of them is extremely difficult (and slow) with pure batch.
I have written a hybrid JScript/batch utility called parseCSV.bat that makes it easy and relatively efficient to correctly parse nearly any CSV file with FOR /F.
parseCSV.bat
#if (#X)==(#Y) #end /* harmless hybrid line that begins a JScrpt comment
::************ Documentation ***********
::parseCSV.bat version 1.0
:::
:::parseCSV [/option]...
:::
::: Parse stdin as CSV and write it to stdout in a way that can be safely
::: parsed by FOR /F. All columns will be enclosed by quotes so that empty
::: columns may be preserved. It also supports delimiters, newlines, and
::: quotes within quoted values. Two consecutive quotes within a quoted value
::: are converted into one quote.
:::
::: Available options:
:::
::: /I:string = Input delimiter. Default is a comma.
:::
::: /O:string = Output delimiter. Default is a comma.
:::
::: /E = Encode output delimiter in value as \D
::: Encode newline in value as \N
::: Encode backslash in value as \S
:::
::: /D = Escape exclamation point and caret for delayed expansion
::: ! becomes ^!
::: ^ becomes ^^
:::
:::parseCSV /?
:::
::: Display this help
:::
:::parseCSV /V
:::
::: Display the version of parseCSV.bat
:::
:::parseCSV.bat was written by Dave Benham. Updates are available at the original
:::posting site: http://www.dostips.com/forum/viewtopic.php?f=3&t=5702
:::
::************ Batch portion ***********
#echo off
if "%~1" equ "/?" (
setlocal disableDelayedExpansion
for /f "delims=: tokens=*" %%A in ('findstr "^:::" "%~f0"') do echo(%%A
exit /b 0
)
if /i "%~1" equ "/V" (
for /f "delims=:" %%A in ('findstr /bc:"::%~nx0 version " "%~f0"') do echo %%A
exit /b 0
)
cscript //E:JScript //nologo "%~f0" %*
exit /b 0
************ JScript portion ***********/
var args = WScript.Arguments.Named,
stdin = WScript.Stdin,
stdout = WScript.Stdout,
escape = args.Exists("E"),
delayed = args.Exists("D"),
inDelim = args.Exists("I") ? args.Item("I") : ",",
outDelim = args.Exists("O") ? args.Item("O") : ",",
quote = false,
ln, c, n;
while (!stdin.AtEndOfStream) {
ln=stdin.ReadLine();
if (!quote) stdout.Write('"');
for (n=0; n<ln.length; n++ ) {
c=ln.charAt(n);
if (c == '"') {
if (quote && ln.charAt(n+1) == '"') {
n++;
} else {
quote=!quote;
continue;
}
}
if (c == inDelim && !quote) c='"'+outDelim+'"';
if (escape) {
if (c == outDelim) c="\\D";
if (c == "\\") c="\\S";
}
if (delayed) {
if (c == "!") c="^!";
if (c == "^") c="^^";
}
stdout.Write(c);
}
stdout.Write( (quote) ? ((escape) ? "\\N" : "\n") : '"\n' );
}
I have also written a script that defines a macro to assist with parsing the most problematic CSV files. See http://www.dostips.com/forum/viewtopic.php?f=3&t=1827 for background information about batch macros with arguments.
define_csvGetCol.bat
::define_csvGetCol.bat version 1.1
::
:: Defines variable LF and macro csvGetCol to be used with
:: parseCSV.bat to parse nearly any CSV file.
::
:: This script must be called with delayedExpansion disabled.
::
:: The %csvGetCol% macro must be used with delayedExpansion enabled.
::
:: Example usage:
::
:: #echo off
:: setlocal disableDelayedExpansion
:: call define_csvGetCol
:: setlocal enableDelayedExpansion
:: for /f "tokens=1-3 delims=," %%A in ('parseCSV /d /e ^<test.csv') do (
:: %== Load and decode column values ==%
:: %csvGetCol% A "," %%A
:: %csvGetCol% B "," %%B
:: %csvGetCol% C "," %%C
:: %== Display the result ==%
:: echo ----------------------
:: for %%V in (A B C) do echo %%V=!%%V!
:: echo(
:: )
::
:: Written by Dave Benham
::
:: Delayed expansion must be disabled during macro definition
:: Define LF to contain a linefeed (0x0A) character
set ^"LF=^
^" The empty line above is critical - DO NOT REMOVE
:: define a newline with line continuation
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
:: Define csvGetCol
:: %csvGetCol% envVarName "Delimiter" FORvar
set csvGetCol=for %%# in (1 2) do if %%#==2 (%\n%
setlocal enableDelayedExpansion^&for /f "tokens=1,2*" %%1 in ("!args!") do (%\n%
endlocal^&endlocal%\n%
set "%%1=%%~3"!%\n%
if defined %%1 (%\n%
for %%L in ("!LF!") do set "%%1=!%%1:\N=%%~L!"%\n%
set "%%1=!%%1:\D=%%~2!"%\n%
set "%%1=!%%1:\S=\!"%\n%
)%\n%
)) else setlocal disableDelayedExpansion ^& set args=
Usage is extremely simple if you know there are no commas or newlines in any values, and delayed expansion is not needed:
test1.csv
"value1 with ""quotes""",value2: No problem!,value3: 2^3=8,value4: (2^2)!=16
value1,,value3,value4
value1,,,value4
value1,,,
,,,value4
test1.bat - no delayed expansion, no commas or newlines in values
#echo off
for /f "tokens=1-4 delims=," %%A in ('parseCSV ^<test1.csv') do (
echo -------------
echo(A=%%~A
echo(B=%%~B
echo(C=%%~C
echo(D=%%~D
echo(
)
--OUTPUT1--
-------------
A=value1 with "quotes"
B=value2: No problem!
C=value3: 2^3=8
D=value4: (2^2)!=16
-------------
A=value1
B=
C=value3
D=value4
-------------
A=value1
B=
C=
D=value4
-------------
A=value1
B=
C=
D=
-------------
A=
B=
C=
D=value4
It is also quite simple when commas are in values if you know of a character that does not exist in any value. Simply specify a unique character for the output delimiter.
test2.csv
"value1 with ""quotes""","value2, No problem!","value3, 2^3=8","value4, (2^2)!=16"
value1,,value3,value4
value1,,,value4
value1,,,
,,,value4
test2.bat - no delayed expansion, no newlines or pipes in values. Note that the entire option must be quoted if the delimiter is a poison character
#echo off
for /f "tokens=1-4 delims=|" %%A in ('parseCSV "/o:|" ^<test2.csv') do (
echo -------------
echo(A=%%~A
echo(B=%%~B
echo(C=%%~C
echo(D=%%~D
echo(
)
--OUTPUT2--
-------------
A=value1 with "quotes"
B=value2, No problem!
C=value3, 2^3=8
D=value4, (2^2)!=16
-------------
A=value1
B=
C=value3
D=value4
-------------
A=value1
B=
C=
D=value4
-------------
A=value1
B=
C=
D=
-------------
A=
B=
C=
D=value4
It only takes a bit more code if values may contain newlines or if you don't know of a character that does not appear in any value. This solution encodes newlines, delimiters, and slashes as \N, \D, and \S. Delayed expansion is needed within the loop to decode the values, so ! and ^ must be escaped as ^! and ^^.
test3.csv
"2^3=8","(2^2)!=16","Success!",Value4
value1,value2,value3,value4
,,,value4
"value1","value2","value3","value4"
"He said, ""Hey cutie.""","She said, ""Drop dead!""","value3 line1
value3 line2",c:\Windows
test3.bat - Allow virtually any valid CSV, without using a macro.
#echo off
setlocal enableDelayedExpansion
:: Define LF to contain a linefeed (0x0A) character
set ^"LF=^
^" The empty line above is critical - DO NOT REMOVE
for /f "tokens=1-4 delims=," %%A in ('parseCSV /e /d ^<test3.csv') do (
%== Load columns with encoded values. The trailing ! is important ==%
set "A=%%~A"!
set "B=%%~B"!
set "C=%%~C"!
set "D=%%~D"!
%== Decode values ==%
for %%L in ("!LF!") do for %%V in (A B C D) do if defined %%V (
set "%%V=!%%V:\N=%%~L!"
set "%%V=!%%V:\D=,!"
set "%%V=!%%V:\S=\!"
)
%== Print results ==%
echo ---------------------
for %%V in (A B C D) do echo(%%V=!%%V!
echo(
)
--OUTPUT3--
---------------------
A=2^3=8
B=(2^2)!=16
C=Success!
D=Value4
---------------------
A=value1
B=value2
C=value3
D=value4
---------------------
A=
B=
C=
D=value4
---------------------
A=value1
B=value2
C=value3
D=value4
---------------------
A=He said, "Hey cutie."
B=She said, "Drop dead!"
C=value3 line1
value3 line2
D=c:\Windows
test4.bat - Allow virtually any valid CSV, but now use the %csvGetCol% macro.
#echo off
:: Delayed expansion must be disabled during macro definition
setlocal disableDelayedExpansion
call define_csvGetCol
:: Delayed expansion must be enabled when using %csvGetCol%
setlocal enableDelayedExpansion
for /f "tokens=1-4 delims=," %%A in ('parseCSV /e /d ^<test3.csv') do (
%== Load and decode column values ==%
%csvGetCol% A "," %%A
%csvGetCol% B "," %%B
%csvGetCol% C "," %%C
%csvGetCol% D "," %%D
%== Print results ==%
echo ---------------------
for %%V in (A B C D) do echo(%%V=!%%V!
echo(
)
Output is identical to test3.bat
If the CSV file is very large, then it is much more efficient to save the output of parseCSV.bat to a temporary file, and then use the FOR /F loop to read the temporary file.
There are still a couple inherent limitations that are true for all FOR /F usage:
1) A single FOR /F cannot parse more than 32 columns.
2) Batch line length restriction of 8191 characters can still be a problem.
No sample data, so solution incomplete.
#ECHO OFF
SETLOCAL enabledelayedexpansion
(
FOR /f "delims=" %%a IN (q27830845.txt) DO (
SET "line=%%a"
SET "line=!line:,,,= , , ,!"
SET "line=!line:,,= , ,!"
FOR /f "tokens=1-4delims=," %%b IN ("!LINE!") DO (
ECHO(%%a--^>^>%%b++%%c++%%d++%%e++
)
)
)>newfile.txt
GOTO :EOF
I used a file named q27830845.txt containing this data for my testing.
col1,col 2,col 3,col4
one,two,three,four
ONE,,THREE,FOUR - no two
ONE,,,FOUR - 3 and 2 missing
,,,Only FOUR
Produces newfile.txt with content
col1,col 2,col 3,col4-->>col1++col 2++col 3++col4++
one,two,three,four-->>one++two++three++four++
ONE,,THREE,FOUR - no two-->>ONE ++ ++THREE++FOUR - no two++
ONE,,,FOUR - 3 and 2 missing-->>ONE ++ ++ ++FOUR - 3 and 2 missing++
,,,Only FOUR-->> ++ ++ ++Only FOUR++
Note that %%a etc may have Space appended. Will no doubt show sensitivity to the characters which have meaning to cmd like ! and %. ++ used simply as an obvious visual separator between fields.
Should be easy but after much searching still can't get it. I need to sort a list that looks like this, according to the number following the second slash:
/1628907159142/20141024021655
/01_B00I7VVZAI_G6/20141028100307
/1358737922754/20141013173229
/1307314535151/20141023185621
...
These are timestamps. First 8 characters = date. I need the list in date order, earliest first. The time doesn't matter. Ouput would look like this:
/1358737922754/20141013173229
/1307314535151/20141023185621
/1628907159142/20141024021655
...
I'm misunderstanding something here. I've tried many permutations of the following, all of which seem to sort based on 1st token. I've used tokens=2, tokens=2*, tokens=1,2 echoing %%H%%G, and more. Only dif is what part of string goes into the file. The list is always ordered according to number following 1st slash.
FOR /f "tokens=2 delims=/" %%G IN ('sort ^<Input.txt') DO (
ECHO %%G >>output.txt
)
I found something like below which was to sort lines based on string following a space on each line. I only modified delims and var name for my case. Not sure why 12 dots are added and removed, but figured ok to leave it.
setlocal enableextensions
for /f "tokens=1,2 delims=/" %%a in (Input.txt) do (
set "_date=............%%b"
call set %%_date:~-12%%=%%a
)
for /f "tokens=1* delims==." %%a in ('set .') do >>output.txt echo %%b %%a
Looks like it should work without delayedexpansion, but it doesn't for me. And I can't get the "call set" to work with DelayedExpansion no matter how I use !marks. Thank you.
You are sorting before extracting tokens. The built-in sort does not provide a way to sort based on a delimiter, so you will have to rearrange the input before sorting. Try something like this:
del temp.txt output.txt
FOR /f "tokens=1-2 delims=/" %%G IN (Input.txt) DO (
ECHO /%%H/%%G >>temp.txt
)
sort <temp.txt >temp2.txt
FOR /f "tokens=1-2 delims=/" %%G IN (temp2.txt) DO (
ECHO /%%H/%%G >>output.txt
)
del temp.txt temp2.txt
Your non-operating code that tries to use environment variables to sort data is easy to fix:
#echo off
setlocal disableDelayedExpansion
:: Clear existing _ variables
for /f "delims==" %%A in ('set _ 2^>nul') do set "%%A="
:: Load the data into _ variables.
:: The date is in the name, and the full line is in the value.
:: A line number is included in name just in case two rows have the same date.
:: I use FINDSTR /N to establish the line numbers.
for /f "tokens=1* delims=:" %%A in ('findstr /n . "input.txt"') do (
for /f "tokens=2 delims=/" %%C in ("%%B") do set "_%%C_%%A=%%B"
)
:: Sort and write result
:: The SET command automatically sorts variables by name
>output.txt (
for /f "tokens=2 delims==" %%A in ('set _') do echo %%A
)
But there is a much simpler solution :-)
I have updated my JSort.bat utility to allow you to sort starting at a given token position.
JSort.bat is a hybrid JScript/batch script that provides much more functionality than the standard Windows SORT command. It is pure script that runs natively on any Windows machine from XP onward. Full documentation is embedded within the script.
JSort.bat is much slower than the native SORT command, and it is limited to a maximum file size of around 10 mb.
Assuming JSort.bat is in your current directory, or better yet, somewhere within your PATH, then your sort operation can be as simple as:
jsort input.txt /t 3 /d "/" >output.txt
Note that I use /T 3 because there is an empty token at the beginning of each line.
Here is the actual JSort.bat script. I don't promise to keep this code up-to-date on this site. The current version can always be found at DosTips.
#if (#X)==(#Y) #end /* Harmless hybrid line that begins a JScript comment
::************ Documentation ***********
::JSORT.BAT version 3.2
:::
:::JSORT [File] [/Option [Value]]...
:::
::: Sort lines of text from stdin and write the result to stdout.
::: JSORT uses an ascending, case sensitive text sort by default.
:::
::: File - If the optional File argument is specified, then JSORT reads lines
::: from the file instead of from stdin. If specified, the File must
::: be the very first argument.
:::
::: Options:
:::
::: /C n - Number of sorted lines to print. Skipped lines are always printed
::: and do not contribute to the count. Default is -1 (all lines).
:::
::: /D String - Specifies the string used to delimit tokens. The delimiter
::: string is always case sensitive. A quote literal " must be escaped
::: as \q, and a backslash literal \ must be escaped as \\.
::: The default value is an empty string, meaning treat the entire
::: line as a single token.
:::
::: /I - Ignore case when sorting
:::
::: /N - Sort consecutive digits as numbers instead of text. The numbers
::: may be embedded within alpha text. JSort supports numbers up to
::: 20 digits long.
:::
::: /O File - Writes the output to File instead of stdout.
:::
::: /P n - Begin sorting at character position n relative to the beginning
::: of the selected token. Lines that do not extend that far are
::: treated as equivalent values, and collate before all other lines.
::: The default value is 1 (first character).
:::
::: /R - Sort the lines in Reverse (descending) order.
:::
::: /S n - Number of lines to skip - default is 0.
::: Skipped lines are not sorted (remain in place)
:::
::: /T n - Specify the token at which to begin sorting. The default value
::: is 1 (first token).
:::
::: /V - Display the version of JSORT.BAT.
:::
::: /? - Display this help
:::
:::JSORT.BAT was written by Dave Benham and originally posted at
:::http://www.dostips.com/forum/viewtopic.php?f=3&t=5595
:::
::************ Batch portion ***********
#echo off
setlocal disableDelayedExpansion
:: Get optional input file
set "infile="
set "test=%~1"
setlocal enableDelayedExpansion
if defined test if "!test:~0,1!" neq "/" (
endlocal
set ^"infile=^<"%~1""
shift /1
) else endlocal
:: Define options
set "options= /?: /i: /c:-1 /n: /p:1 /r: /s:0 /v: /d:"" /t:1 /o:"" "
:: Set default option values
for %%O in (%options%) do for /f "tokens=1,* delims=:" %%A in ("%%O") do set "%%A=%%~B"
:: Get options
:loop
if not "%~1"=="" (
setlocal enableDelayedExpansion
set "test=!options:* %~1:=! "
if "!test!"=="!options! " (
>&2 echo Error: Invalid option %~1
exit /b 1
) else if "!test:~0,1!"==" " (
endlocal
set "%~1=1"
) else (
endlocal
set "%~1=%~2"
shift /1
)
shift /1
goto :loop
)
:: Display help
if defined /? (
for /f "delims=: tokens=*" %%A in ('findstr "^:::" "%~f0"') do echo(%%A
exit /b 0
)
:: Display version
if defined /v (
for /f "delims=: tokens=*" %%A in ('findstr /bc:"::JSORT.BAT version" "%~f0"') do echo %%A
exit /b 0
)
:: Transform and validate options
set /a "case=0%/i%, num=0%/n%, pos=%/p%-1, tok=%/t%-1, order=1-2*0%/r%, 1/!(0x80000000&pos), 1/!(0x80000000&tok)" 2>nul || (
>&2 echo Error: Invalid option value.
exit /b 1
)
set "outfile="
if defined /o set ^"outfile=^>"%/o%""
:: Perform the sort
%infile% %outfile% cscript //E:JScript //nologo "%~f0" %case% %num% %pos% %order% %/s% %/c% %tok% "%/d%"
exit /b 0
************* JScript portion **********/
var array=new Array(),
nocase =WScript.Arguments.Item(0),
numeric=WScript.Arguments.Item(1),
pos =WScript.Arguments.Item(2),
order =WScript.Arguments.Item(3),
skip =WScript.Arguments.Item(4),
count =WScript.Arguments.Item(5),
token =WScript.Arguments.Item(6),
delim =WScript.Arguments.Item(7).replace(/\\(?!q|\\)/g,'').replace(/\\\\/g,'\\s').replace(/\\q/g,'"').replace(/\\s/g,'\\');
while (!WScript.StdIn.AtEndOfStream) {
if (skip > 0) {
WScript.Echo(WScript.StdIn.ReadLine());
skip-=1
} else {
var expanded="", num="", raw=WScript.StdIn.ReadLine(), upper=((nocase==1)?raw.toUpperCase():raw);
for( var i=pos+FindToken(raw,delim,token); i<raw.length; i++ ) {
var c=upper.substr(i,1);
if (numeric==1 && c>="0" && c<="9") {
num+=c;
} else {
if (num != "") {
num="00000000000000000000" + num;
expanded+=num.substr(num.length-20);
num="";
}
expanded+=c;
}
}
if (num != "") {
num="00000000000000000000" + num;
expanded+=num.substr(num.length-20);
}
var obj={expanded:expanded, raw:raw};
array.push(obj);
}
}
if (count<0) count=array.length;
if (count>array.length) count=array.length;
array.sort(function(a,b){return order*((a.expanded>b.expanded)-(a.expanded<b.expanded));});
for (var i=0; i<count; i++) WScript.Echo(array[i].raw);
function FindToken(str, str2, n) {
if (n>0 && str2=="") return str.length;
var rtn = 0;
for( var i=n; i>0; i-- ) {
rtn = str.indexOf(str2,rtn);
if (rtn<0) return str.length;
rtn+=str2.length;
}
return rtn;
}
I have a set of data like this
7859 10000:00 7859 10000:00 (xfer#1, to-check=1033/1035)
32768 000:17 22174479 10000:00 (xfer#2, to-check=1032/1035)
They are read from a file and passed line by line to a method inside my batch script
What I want to do in that method is to extract only
7859
22174479
from this lines, basically whatever is after "\d+:\d\d\s+", then what follows are the numbers that I need and then another "\d\d.*"
Is this possible using only batch script regular expression and search and replace?
I tried and read a bunch of articles but could not find a solution
In the and I want to add the numbers
Thank you
EDIT
Based on Andrei's comment to David Ruhmann's answer, Andrei wants the token that is 2 positions before (xfer#, not the 3rd token from the beginning.
Do note that batch is not the best language to use for regex! Cmd processes the input one line at a time, whereas regex allows for multi-line processing.
It sounds like you just need to perform a token grab from the lines. Assuming the more complete regex for the line looks like this [\d+\s+\d+:\d\d\s+]+\(xfer#\d+, to-check=\d+/\d+\).
This allows us to know that there are constant delimiters in the line. : colons, and \s+ whitespace. From there it is just a matter of using those anchors to determine the token position.
Extract the third token delimited by single line whitespace from the line.
for /f "tokens=3" %%A in ("line") do echo %%A
Extract the second token delimited by single line whitespace from the second token delimited by colons from the line.
for /f "tokens=2 delims=:" %%A in ("line") do (
for /f "tokens=2" %%B in ("%%A") do echo %%B
)
Update
Extract the second token before the last colon.
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "Line=32768 004:47 2686976 2200:03 11707819 10000:01 (xfer#5264, to-check=1020/6975)"
set "Last="
for /f "delims=" %%A in ('echo("%Line::="^&echo("%"') do (
for /f "tokens=2" %%B in ("%%A") do (
if defined This set "Last=!This!"
set "This=%%B"
)
)
echo %Last%
endlocal
pause >nul
Limitations
Lines containing an odd number of double quotation marks " will cause the script to crash. One method to prevent this is to strip out the quotations before the for loop with set Line=%Line:"=%.
Based on your comment to David Ruhmann's answer, you want the token that is 2 positions before the (xfer# string. I suppose it can be done using native batch commands, but that is a nasty problem.
I am assuming you are restricted to commands that are native to Windows - no downloaded executables.
I'm hoping that you may use JScript, since it is native to Windows.
I have written a hybrid JScript/Batch utility script named "REPL.BAT" that performs regex search and replace. It is an amazingly useful utility, despite not requiring much code. The utility makes the solution very simple.
I use FINDSTR to filter out the lines that don't meet the template of at least 2 space delimted tokens prior to (xfer#. I pipe those results to my REPL utility and preserve only the desired token. The result is sent to stdout.
findstr /r /c:" [^ ][^ ]* [^ ][^ ]* (xfer#" test.txt | repl ".* ([^ ]+) ([^ ]+) \(xfer#.*" "$1"
Here is the code for the REPL.BAT utility script. Full documentation is embedded within the script.
#if (#X)==(#Y) #end /* Harmless hybrid line that begins a JScript comment
::************ Documentation ***********
:::
:::REPL Search Replace [Options [SourceVar]]
:::REPL /?
:::
::: Performs a global search and replace operation on each line of input from
::: stdin and prints the result to stdout.
:::
::: Each parameter may be optionally enclosed by double quotes. The double
::: quotes are not considered part of the argument. The quotes are required
::: if the parameter contains a batch token delimiter like space, tab, comma,
::: semicolon. The quotes should also be used if the argument contains a
::: batch special character like &, |, etc. so that the special character
::: does not need to be escaped with ^.
:::
::: If called with a single argument of /? then prints help documentation
::: to stdout.
:::
::: Search - By default this is a case sensitive JScript (ECMA) regular
::: expression expressed as a string.
:::
::: JScript syntax documentation is available at
::: http://msdn.microsoft.com/en-us/library/ae5bf541(v=vs.80).aspx
:::
::: Replace - By default this is the string to be used as a replacement for
::: each found search expression. Full support is provided for
::: substituion patterns available to the JScript replace method.
::: A $ literal can be escaped as $$. An empty replacement string
::: must be represented as "".
:::
::: Replace substitution pattern syntax is documented at
::: http://msdn.microsoft.com/en-US/library/efy6s3e6(v=vs.80).aspx
:::
::: Options - An optional string of characters used to alter the behavior
::: of REPL. The option characters are case insensitive, and may
::: appear in any order.
:::
::: I - Makes the search case-insensitive.
:::
::: L - The Search is treated as a string literal instead of a
::: regular expression. Also, all $ found in Replace are
::: treated as $ literals.
:::
::: E - Search and Replace represent the name of environment
::: variables that contain the respective values. An undefined
::: variable is treated as an empty string.
:::
::: M - Multi-line mode. The entire contents of stdin is read and
::: processed in one pass instead of line by line. ^ anchors
::: the beginning of a line and $ anchors the end of a line.
:::
::: X - Enables extended substitution pattern syntax with support
::: for the following escape sequences:
:::
::: \\ - Backslash
::: \b - Backspace
::: \f - Formfeed
::: \n - Newline
::: \r - Carriage Return
::: \t - Horizontal Tab
::: \v - Vertical Tab
::: \xnn - Ascii (Latin 1) character expressed as 2 hex digits
::: \unnnn - Unicode character expressed as 4 hex digits
:::
::: Escape sequences are supported even when the L option is used.
:::
::: S - The source is read from an environment variable instead of
::: from stdin. The name of the source environment variable is
::: specified in the next argument after the option string.
:::
::************ Batch portion ***********
#echo off
if .%2 equ . (
if "%~1" equ "/?" (
findstr "^:::" "%~f0" | cscript //E:JScript //nologo "%~f0" "^:::" ""
exit /b 0
) else (
call :err "Insufficient arguments"
exit /b 1
)
)
echo(%~3|findstr /i "[^SMILEX]" >nul && (
call :err "Invalid option(s)"
exit /b 1
)
cscript //E:JScript //nologo "%~f0" %*
exit /b 0
:err
>&2 echo ERROR: %~1. Use REPL /? to get help.
exit /b
************* JScript portion **********/
var env=WScript.CreateObject("WScript.Shell").Environment("Process");
var args=WScript.Arguments;
var search=args.Item(0);
var replace=args.Item(1);
var options="g";
if (args.length>2) {
options+=args.Item(2).toLowerCase();
}
var multi=(options.indexOf("m")>=0);
var srcVar=(options.indexOf("s")>=0);
if (srcVar) {
options=options.replace(/s/g,"");
}
if (options.indexOf("e")>=0) {
options=options.replace(/e/g,"");
search=env(search);
replace=env(replace);
}
if (options.indexOf("l")>=0) {
options=options.replace(/l/g,"");
search=search.replace(/([.^$*+?()[{\\|])/g,"\\$1");
replace=replace.replace(/\$/g,"$$$$");
}
if (options.indexOf("x")>=0) {
options=options.replace(/x/g,"");
replace=replace.replace(/\\\\/g,"\\B");
replace=replace.replace(/\\b/g,"\b");
replace=replace.replace(/\\f/g,"\f");
replace=replace.replace(/\\n/g,"\n");
replace=replace.replace(/\\r/g,"\r");
replace=replace.replace(/\\t/g,"\t");
replace=replace.replace(/\\v/g,"\v");
replace=replace.replace(/\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4}/g,
function($0,$1,$2){
return String.fromCharCode(parseInt("0x"+$0.substring(2)));
}
);
replace=replace.replace(/\\B/g,"\\");
}
var search=new RegExp(search,options);
if (srcVar) {
WScript.Stdout.Write(env(args.Item(3)).replace(search,replace));
} else {
while (!WScript.StdIn.AtEndOfStream) {
if (multi) {
WScript.Stdout.Write(WScript.StdIn.ReadAll().replace(search,replace));
} else {
WScript.Stdout.WriteLine(WScript.StdIn.ReadLine().replace(search,replace));
}
}
}
:: Does %variable% =~ s/old/new/
setlocal ENABLEDELAYEDEXPANSION
for /f "delims=" %%a in ('echo !variable! ^|perl -pe "s/regexp/replace/" ') do set variable=%%a
The easiest and most flexible way to accomplish what you want would be to use awk (regexp examples) or sed (for example: sed -i -r -e "s/(\d+:\d\d\s+)\d+/\1replacementstring/g" filename) from GnuWin32, which both support Perl regexp syntax. I think what you're involved in is exactly what awk was designed for.
If you're stuck using only what's available without having to use 3rd party tools, you can perform regexp matches using vbscript. You can call vbscript by echoing the script to a .vbs file, calling cscript vbsfile, and capturing its output. Here's a proof of concept.
#echo off & setlocal enabledelayedexpansion
:: rxp.bat
:: rxp /? for usage instructions
if #%4==# goto usage
set global=false
set replace=false
for %%I in (%*) do (
if not #!next!==# (
if !next!==string set string=%%I
if !next!==pattern set pattern=%%I
if !next!==replace set replace=%%I
set next=
)
if #%%I==#/s set next=string
if #%%I==#/p set next=pattern
if #%%I==#/r set next=replace
if #%%I==#/g set global=true
)
if #%string==# goto usage
if #%pattern==# goto usage
set string=!string:"=""!
set string=!string:\=!
set pattern=!pattern:"=""!
set pattern=!pattern:\=!
if #!replace!==#false (
call :rxp !string:~1,-1! !pattern:~1,-1! !global!
) else (
set replace=!replace:"=""!
set replace=!replace:\=!
call :rxp !string:~1,-1! !pattern:~1,-1! !global! !replace:~1,-1!
)
goto :EOF
:rxp string pattern global replacement
echo Set rxp = New RegExp>regexp.vbs
echo rxp.Pattern = %2>>regexp.vbs
echo rxp.Global = %3>>regexp.vbs
if #%4==# (
echo Set res = rxp.Execute^(%1^)>>regexp.vbs
echo For Each match in res>>regexp.vbs
echo Wscript.Echo match.value>>regexp.vbs
echo Next>>regexp.vbs
) else (
echo Wscript.echo rxp.Replace^(%1, %4^)>>regexp.vbs
)
cscript /nologo regexp.vbs
del /q regexp.vbs
goto :EOF
:usage
echo Usage: %~nx0 /s "string" /p "regexp" [/g] [/r "replacement text"]
echo;
echo /s -- search string
echo;
echo /p -- regular expression pattern
echo Example: /p "<[^>]+>" to search for markup tags
echo matches ^<span class='a'^> or similar
echo;
echo /r -- replacement text (optional)
echo If specified, replace the matched text
echo Example: /p "(<div class=')blue('>)" /r "$1red$2"
echo matches ^<div class='blue'^>
echo replaces match with ^<div class='red'^>
echo;
echo /g -- global match (optional)
echo match every occurrence (matches only the first by default)
echo;
echo notes: If the regexp pattern includes capturing parentheses, use ^$1-^$9 as
echo backreferences in your replacement text. If any of your strings include
echo quotation marks, they can be escaped with a backslash (\).
echo;
echo Example:
echo %~nx0 /s "text begin <div id=\"foo\"> text end" /p "(<div)[^>]+(>)"
echo /r "$1 class=\"bar\"$2"
echo;
echo matches ^<div id="foo"^>, replaces match with ^<div class="bar"^>
echo output: text begin ^<div class="bar"^> text end
example output:
C:\Users\me\Desktop>rxp /s "7859 10000:00 7849 10000:00 (xfer#1, to-check=1033/1035)" /p "(\d+:\d\d\s+)\d+" /r "$1foo"
7859 10000:00 foo 10000:00 (xfer#1, to-check=1033/1035)
C:\Users\me\Desktop>rxp
Usage: rxp.bat /s "string" /p "regexp" [/g] [/r "replacement text"]
/s -- search string
/p -- regular expression pattern
Example: /p "<[^>]+>" to search for markup tags
matches <span class='a'> or similar
/r -- replacement text (optional)
If specified, replace the matched text
/g -- global match (optional)
match every occurrence (matches only the first by default)
notes: If the regexp pattern includes capturing parentheses, use $1-$9 as
backreferences in your replacement text. If any of your strings include
quotation marks, they can be escaped with a backslash (\).
Example:
rxp.bat /s "text begin <div id=\"foo\"> text end" /p "(<div)[^>]+(>)"
/r "$1 class=\"bar\"$2"
matches <div id="foo">, replaces match with <div class="bar">
output: text begin <div class="bar"> text end
I need a batch file contents to copy file A to file B after removing the CR LF
I have found the following but it is simply taking actual value of %1 and putting into a file without cr lf.
REM Copy and Remove Line Feeds
#echo off
echo %1> %2
rem <nul set /p ".=%1 > c:/temp/%2.txt
I need to remove all the CR LFs from File A and put the results in File B
The Batch file below do what you want in the fastest way:
#echo off
setlocal DisableDelayedExpansion
(for /F "usebackq delims=" %%a in (%1) do (
set /P "=%%a" < NUL
)) > %2
You must put files A and B in the parameters: test.bat A.txt B.txt
Antonio
There are a number of free 3rd party utilities that could be downloaded to make this task easy.
I have written a REPL.BAT hybrid batch/JScript utility that conveinently performs regex search and replace on files. It is extremely flexible and quite fast.
It is very easy to do what you want with this utility.
type A.txt|repl "\r|\n" "" m >B.txt
Here is the REPL.BAT script. Full documentation is embedded within the script:
#if (#X)==(#Y) #end /* Harmless hybrid line that begins a JScript comment
::************ Documentation ***********
:::
:::REPL Search Replace [Options [SourceVar]]
:::REPL /?
:::
::: Performs a global search and replace operation on each line of input from
::: stdin and prints the result to stdout.
:::
::: Each parameter may be optionally enclosed by double quotes. The double
::: quotes are not considered part of the argument. The quotes are required
::: if the parameter contains a batch token delimiter like space, tab, comma,
::: semicolon. The quotes should also be used if the argument contains a
::: batch special character like &, |, etc. so that the special character
::: does not need to be escaped with ^.
:::
::: If called with a single argument of /? then prints help documentation
::: to stdout.
:::
::: Search - By default this is a case sensitive JScript (ECMA) regular
::: expression expressed as a string.
:::
::: JScript syntax documentation is available at
::: http://msdn.microsoft.com/en-us/library/ae5bf541(v=vs.80).aspx
:::
::: Replace - By default this is the string to be used as a replacement for
::: each found search expression. Full support is provided for
::: substituion patterns available to the JScript replace method.
::: A $ literal can be escaped as $$. An empty replacement string
::: must be represented as "".
:::
::: Replace substitution pattern syntax is documented at
::: http://msdn.microsoft.com/en-US/library/efy6s3e6(v=vs.80).aspx
:::
::: Options - An optional string of characters used to alter the behavior
::: of REPL. The option characters are case insensitive, and may
::: appear in any order.
:::
::: I - Makes the search case-insensitive.
:::
::: L - The Search is treated as a string literal instead of a
::: regular expression. Also, all $ found in Replace are
::: treated as $ literals.
:::
::: E - Search and Replace represent the name of environment
::: variables that contain the respective values. An undefined
::: variable is treated as an empty string.
:::
::: M - Multi-line mode. The entire contents of stdin is read and
::: processed in one pass instead of line by line. ^ anchors
::: the beginning of a line and $ anchors the end of a line.
:::
::: X - Enables extended substitution pattern syntax with support
::: for the following escape sequences:
:::
::: \\ - Backslash
::: \b - Backspace
::: \f - Formfeed
::: \n - Newline
::: \r - Carriage Return
::: \t - Horizontal Tab
::: \v - Vertical Tab
::: \xnn - Ascii (Latin 1) character expressed as 2 hex digits
::: \unnnn - Unicode character expressed as 4 hex digits
:::
::: Escape sequences are supported even when the L option is used.
:::
::: S - The source is read from an environment variable instead of
::: from stdin. The name of the source environment variable is
::: specified in the next argument after the option string.
:::
::************ Batch portion ***********
#echo off
if .%2 equ . (
if "%~1" equ "/?" (
findstr "^:::" "%~f0" | cscript //E:JScript //nologo "%~f0" "^:::" ""
exit /b 0
) else (
call :err "Insufficient arguments"
exit /b 1
)
)
echo(%~3|findstr /i "[^SMILEX]" >nul && (
call :err "Invalid option(s)"
exit /b 1
)
cscript //E:JScript //nologo "%~f0" %*
exit /b 0
:err
>&2 echo ERROR: %~1. Use REPL /? to get help.
exit /b
************* JScript portion **********/
var env=WScript.CreateObject("WScript.Shell").Environment("Process");
var args=WScript.Arguments;
var search=args.Item(0);
var replace=args.Item(1);
var options="g";
if (args.length>2) {
options+=args.Item(2).toLowerCase();
}
var multi=(options.indexOf("m")>=0);
var srcVar=(options.indexOf("s")>=0);
if (srcVar) {
options=options.replace(/s/g,"");
}
if (options.indexOf("e")>=0) {
options=options.replace(/e/g,"");
search=env(search);
replace=env(replace);
}
if (options.indexOf("l")>=0) {
options=options.replace(/l/g,"");
search=search.replace(/([.^$*+?()[{\\|])/g,"\\$1");
replace=replace.replace(/\$/g,"$$$$");
}
if (options.indexOf("x")>=0) {
options=options.replace(/x/g,"");
replace=replace.replace(/\\\\/g,"\\B");
replace=replace.replace(/\\b/g,"\b");
replace=replace.replace(/\\f/g,"\f");
replace=replace.replace(/\\n/g,"\n");
replace=replace.replace(/\\r/g,"\r");
replace=replace.replace(/\\t/g,"\t");
replace=replace.replace(/\\v/g,"\v");
replace=replace.replace(/\\x[0-9a-fA-F]{2}|\\u[0-9a-fA-F]{4}/g,
function($0,$1,$2){
return String.fromCharCode(parseInt("0x"+$0.substring(2)));
}
);
replace=replace.replace(/\\B/g,"\\");
}
var search=new RegExp(search,options);
if (srcVar) {
WScript.Stdout.Write(env(args.Item(3)).replace(search,replace));
} else {
while (!WScript.StdIn.AtEndOfStream) {
if (multi) {
WScript.Stdout.Write(WScript.StdIn.ReadAll().replace(search,replace));
} else {
WScript.Stdout.WriteLine(WScript.StdIn.ReadLine().replace(search,replace));
}
}
}