I wanted to make help generator for all command in help in Windows cmd and write it to separate files. So you are asking /? on all commands that are on the list when you type help in cmd.
Here are the main part of my code:
rem mypath - it's a folder where I put my results
rem In help all command are written by capitals letters
for /f "tokens=1 usebackq" %%i in (`help^|findstr /B /R "[QWERTYUIOPASDFGHJKLZXCVBNM][QWERTYUIOPASDFGHJKLZXCVBNM]"`) do (
if NOT "%%i"=="GRAFTABL" (
if NOT "%%i"=="DISKPART" (
if NOT "%%i"=="SC" (
help %%i > !mypath!\%%i.txt
)
)
)
)
I use all sequence from [Q..M] in my Regular exp because there are some problems with just set of [A-Z]
But the problem is that in my FOR and IF files - there are help for REM command. Does anyone have any idea why is it so ?
To fix it I use:
FOR/? >%mypath%\FOR.txt
IF/? >%mypath%\IF.txt
But I can't understand why it is so.
The code you posted in your question gives the correct result for me (even before I reformatted it a bit).
See Why does findstr not handle case properly (in some circumstances)? for an explanation of why [A-Z] does not work properly with FINDSTR. For an exhaustive list of known FINDSTR quirks, see What are the undocumented features and limitations of the Windows FINDSTR command?
A better way to filter out command names is to look for lines that begin with at least one non-space character, followed by any number of additional non-space characters, followed by 2 spaces.
If you want to ignore certain commands, you can simply use an additional FINDSTR with the /V option.
The solution becomes a reasonable one liner that can run from the command prompt without a batch script:
for /f %A in ('help^|findstr /rc:"^[^ ][^ ]* "^|findstr /v "GRAFTABL DISKPART SC"') do #help %A >%A.txt
Or as code that can be plugged into your script:
for /f %%A in (
'help^|findstr /rc:"^[^ ][^ ]* "^|findstr /v "GRAFTABL DISKPART SC"'
) do help %%A >"!mypath!\%%A.txt"
EDIT - 2015-10-11
The first and last lines of HELP output start with the word For (mixed case), on my English machine. That word happens to be a valid command with help, so the FOR.TXT file gets created 3 times.
I presume that all languages use mixed case for the first and last line. It is not hard to refine the FINDSTR filter to exclude any line where the 2nd character is space or a lower case character:
for /f %A in ('help^|findstr /rvc:"^.[abcdefghijklmnopqrstuvwxyz ]"^|findstr /v "GRAFTABL DISKPART SC"') do #help %A >%A.txt
I couldn't reproduce your issue, but this worked correctly for me and I found a simpler regular expression:
#echo off
for /f %%i in ('help^|findstr /B /R [A-Z][^^^^o]') do (
if NOT "%%i"=="GRAFTABL" (
if NOT "%%i"=="DISKPART" (
if NOT "%%i"=="SC" (
help %%i > %%i.txt
)
)
)
)
Related
I have 324 files on a Windows 10 machine which are named in the following pattern:
[7 Numbers] [Space] [Last name] [Space] [First name]
And I need them to be:
[Last name] [Space] [First name] [Space] [7 Numbers]
I have done some quick research and found that I could write a batch script utilizing the 'rename' function:
#echo off
rename “y:\*.txt” “???-Test1.*”
However, I was unable to find out how I can program the script to take the first 7 chracters and put them to the end.
Any help is appreciated.
Given the little detail on the exact formatting of your structures, i.e what happens in the event a surname has a split like van Halen which also now contains a space:
anyway, this will cater for the situation as you've mentioned only and not for names/surnames containing spaces.
#echo off
for /f "tokens=1-3*" %%i in ('dir /b /a-d *.txt ^| findstr /R "^[1-9]"') do echo ren "%%i %%j %%k" "%%~nk %%~nj %%~ni%%~xk"
Note this example will simply echo the command and not perform the actual rename. You need to test it first before you do the renaming. Once you are happy with the result printed to console, then remove echo from the line.
Note. findstr is important here as we need to only perform the action if the file starts with numbers. You can define the findstr filter even more if you want to be more specific. Here I just focused on numbers in the beginning of any .txt file considering no name or surname should start with a number., Unless you're 50cent or some other random rapper.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
rem The following setting for the source directoryis a name
rem that I use for testing and deliberately includes spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files\t w o"
FOR %%b IN ("%sourcedir%\??????? * *.txt") DO FOR /f "tokens=1*delims= " %%u IN ("%%~nb") DO SET /a junk=0&SET /a "junk=1%%u" 2>nul&IF !junk! geq 10000000 IF !junk! leq 19999999 ECHO REN "%%b" "%%v %%u.txt"
GOTO :EOF
Please note that this routine uses delayedexpansion
The first for puts the absolute filename of each file matching the mask into %%b
The second partitions the name part of the filename (%%~nb) into that part before the first space (token 1) to %%u and the remainder (token *) to %%v
junk is then set to 0 and then reset to the value of 1%%u. set /a will leave junk unchanged (therefore, 0) if %%u is not a numeric string (the 2>nul suppresses the error message) so if %%u is numeric, junk will be set to 10000000 ... 19999999.
Use !junk! to access the run-time value of junk, check it is within range and if so, echo the ren required.
Remove the echo keyword before the ren after checking the resultant report to actually rename the files.
Just to be thorough, I'll state here my whole project and what I'm aiming at.
I intend to adapt a shell script to work in Windows cmd, as this is intended for people who are not going to have some sophisticate language available.
for g in $(curl -Ls https://api.chess.com/pub/player/hikaru/games/archives | jq -rc ".archives[]") ; do curl -Ls "$g" | jq -rc ".games[].pgn" ; done >> games.pgn
For some reason, Chess.com's API doesn't have a very important feature that Lichess' does, to export all games of a single player, so what I can do manually is to use https://api.chess.com/pub/player/hikaru/games/archives to export all available monthly archives and then hit the API for each one of them. (hikaru inside this will be a set variable, it's the nickname of the desired player to export).
The result for this command is something like
{"archives":["https://api.chess.com/pub/player/hikaru/games/2015/11","https://api.chess.com/pub/player/hikaru/games/2015/12","https://api.chess.com/pub/player/hikaru/games/2016/02","https://api.chess.com/pub/player/hikaru/games/2016/03","https://api.chess.com/pub/player/hikaru/games/2016/04","https://api.chess.com/pub/player/hikaru/games/2016/05"]}
to which I only have to append /pgn to get the desired result.
Obviously, cmd doesn't have jq available, so this involves "parsing" the string inside a batch file.
I figured if I just could replace every occurrence of " with a linebreak and echo the results, I could then use find (or findstr) to easily get a list of lines that only would need to be prefaced with curl and appended with /pgn to get my final result.
The big question is: how do I replace " with a linebreak in cmd? I found a few answers, but none of them seems to work with a special character, part of the problem is that I also didn't understand these answers enough to try and adapt them.
A second way of perhaps achieving the same result would be replacing [, ] and , with line breaks, but then I would also have to worry with deleting the final " to append /pgn, so if I'm able to do the former, it would be cleaner.
in batch/cmd, a for loop is used to process a list (separated by default delimiters like space, tab, comma). So just replace [ and ] with a space or comma, and you have a nice list to split. Finally, use find to filter the output to the relevant parts and you're done:
#Echo off
setlocal
set "string={"archives":["https://api.chess.com/pub/player/hikaru/games/2015/11","https://api.chess.com/pub/player/hikaru/games/2015/12","https://api.chess.com/pub/player/hikaru/games/2016/02","https://api.chess.com/pub/player/hikaru/games/2016/03","https://api.chess.com/pub/player/hikaru/games/2016/04","https://api.chess.com/pub/player/hikaru/games/2016/05"]}"
set "string=%string:[= %"
set "string=%string:]= %"
for %%a in (%string%) do echo %%~a|find "/"
Output:
https://api.chess.com/pub/player/hikaru/games/2015/11
https://api.chess.com/pub/player/hikaru/games/2015/12
https://api.chess.com/pub/player/hikaru/games/2016/02
https://api.chess.com/pub/player/hikaru/games/2016/03
https://api.chess.com/pub/player/hikaru/games/2016/04
https://api.chess.com/pub/player/hikaru/games/2016/05
(in case you wonder: the tilde in echo %%~a removes surrounding quotes)
Stephan's answer gave me the directions I needed to research more and build my own solution. This is not the final script to my project, but it does solve every problem presented in my original question:
#echo off
setLocal enabledelayedexpansion
for /f "delims=" %%a in (input.txt) do (
for %%b in (%%a) do (
set string=%%b
set "string=!string:[=,!"
set "string=!string:]=,!"
echo !string!>>replaced.txt
)
)
for /f "delims=" %%c in (replaced.txt) do (
for %%d in (%%c) do (
echo %%~d>>echo.txt
)
)
for /f %%e in (echo.txt) do echo curl %%~e/pgn|find ".">>list.txt
I basically run 3 sets of loops, the first one loads my input (this could not be done via set because there's a size limit, using a nested loop works around that) and replaces [ and ] for commas.
The second loop sorts again the output. This is done basically to trim unwanted characters from the first and last line.
The last loop generates a list of curl commands that will later be executed into a PGN file (which is a chess file).
This ends the scope of the question, but since my project wasn't that complex, I'll present it's final version, which improves on Compo's answer, in case someone else stumbles upon this question:
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: Chess.com and Lichess API Scraper ::
:: Author: fabiorzfreitas ::
:: Extract all games from a player from Chess.com and Lichess ::
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:: This tool uses Chess.com and Lichess APIs to extract all games from a given player. ::
#echo off
setLocal enabledelayedexpansion
echo.
echo.
echo.
echo All input must be lowcase!
echo.
echo You can skip the input bellow by pressing Enter
echo.
echo.
echo.
set /p lichess="Input Lichess nickname and press Enter: "
set /p chess="Input Chess.com nickname and press Enter: "
echo.
:Lichess
if not defined lichess goto :Chess
curl https://lichess.org/api/games/user/%lichess% >> Games.pgn
:Chess
if not defined chess goto :End
(for /f "usebackq tokens=2 delims=[]" %%g in (`curl https://api.chess.com/pub/player/%chess%/games/archives`) do (
for %%h In (%%g) do curl "%%~h/pgn" >> Games.pgn
)
)
:End
exit
Based upon your own answer, it seems as if you could remove at least one of those steps by using the brackets [ and ], as delimiters.
You could also nest a for loop within another instead of having individual ones and writing to files.
Here it is as a single line batch-file:
#(For /F "UseBackQ Tokens=2 Delims=[]" %%G In ("input.txt") Do #For %%H In (%%G) Do #Echo curl.exe "%%~H/pgn") 1>"list.txt"
To do it directly in cmd:
(For /F "UseBackQ Tokens=2 Delims=[]" %G In ("input.txt") Do #For %H In (%G) Do #Echo curl.exe "%~H/pgn") 1>"list.txt"
I try to write a batch file that parses a file to create another one with its content.
But in the new one I will ignore every line which begin with the -Dremote pattern.
Here is my file
-nl
fr_yy
-clean
-vmargs
-Dgma.environnement=staging
-Duser.timezone=CET
-Dgma.communication=remote
-Dgma.security.disable=false
-Xms256M
-Xmx768M
-XX:PermSize=64m
-XX:MaxPermSize=128m
-Dlogback.configurationFile=file:eclipse/conf-log/logback-error.xml
-Dshut.monitor.active=true
-Dshut.monitor.home=\\mynas05\GMData\Projets\RefonteUtilisateurs\Contrats\shut
-Dshut.applicationRuntimeEnv.systemPropertyKey=gma.environnement-nl
-Dremote_server_MessageWar=http://xxx.xxx.yy
-Dremote_port_MessageWar=40110
-Dremote_server_SinistreWar=http://xxx.xxx.yy
-Dremote_port_SinistreWar=40110
-Dremote_server_FacturationTiersWar=http://xxx.xxx.yy
And here is the code
for /f "tokens=*" %%A in (%tempFile%) do (
set test=%%A
IF NOT "!test:~0,7!"=="-Dremote"( type %%i>>%iniFile%)
)
But everything is copied in the iniFile...
findstr /v /b /l /c:"-Dremote" "%tempFile%" >"%iniFile%"
(Test with a dummy %iniFile% first, of course...)
There are a few errors in one line. Try this:
IF NOT "!test:~0,8!"=="-Dremote" (echo %%A>>%iniFile%)
You miscounted (-Dremote has 8 characters, not 7).
Use echo instead of type.
There is a space in the wrong position.
The wrong variable is used.
(I hope you are aware that you'll have to use delayed expansion (it's not in your code).)
Change 7 to 8 "-Dremote" has 8 characters.
Add a SPACE after "-Dremote" before the round bracket.
setlocal enabledelayedexpansion
for /f "tokens=*" %%A in (%tempFile%) do (
set test=%%A
IF NOT "!test:~0,8!"=="-Dremote" ( echo !test!>>%iniFile%)
)
A quick edit should fix it:
for /f "tokens=*" %%A in (%tempFile%) do (
set test=%%A
IF NOT "!test:~0,7!"=="-Dremote"( echo !test!>>%iniFile%)
)
I'm trying to remove the first 10 characters from multiple lines inside a text file using a batch script, then output the results to a new file. I ran across this and it got me pointed in the right direction but the final output isn't working.
Here's what I've got so far:
setLocal EnableDelayedExpansion
CSCRIPT /nologo %windir%\System32\prnport.vbs -l > c:\IPPorts.txt
type c:\IPPorts.txt | findstr IP_ > c:\IPPorts2.txt
for /f "tokens=*" %%a in (c:\IPPorts2.txt) do (set line=%%a set chars=!line:~10! > c:\IPPorts3.txt)
for /f "delims=" %%x in (c:\IPPorts3.txt) do CSCRIPT /nologo %windir%\System32\prnport.vbs -d -r %%x
The 2nd line exports a list of printer ports to a file named IPPorts.txt. The 3rd finds the lines with "IP_" in them and exports to IPPorts2.txt. The 4th line is supposed to remove unneeded text (which it isn't doing) and export to IPPorts3.txt. And the last line will take the results from IPPorts3.txt and then delete those ports.
IPPorts.txt is as follows:
Server name
Port name IP_172.20.51.11
Host address 172.20.51.11
Protocol RAW
Port number 9100
SNMP Disabled
These lines are repeated for every port, of which there are several. Since I only need the line containing the port name, IPPorts2.txt looks like this:
Port name IP_172.20.51.11
Port name IP_172.20.52.58
Port name IP_172.20.53.16
Port name IP_172.20.54.19
Port name IP_172.20.55.15-1
Port name IP_172.20.55.15
Port name IP_172.20.55.11
Where I'm having trouble is removing the "Port name " portion of the lines (the first 10 characters). I want the output to read on each line as "IP_X.X.X.X". The problem is the 3rd file is always empty.
Where am I going wrong? Any help is greatly appreciated.
EDIT:
This is further down under Endoro's answer, but I thought it might be nice to post the answer here. Here's what I changed the 4th line to:
for /f "tokens=* delims=" %%c in ('type c:\IPPorts2.txt') do (
set LINE=%%c
>> c:\IPPorts3.txt echo !LINE:~10!
)
This has corrected my problems. Thanks everyone!
try this:
(for /f "tokens=3" %%i in (IPPorts2.txt) do #echo %%i)>IPPorts3.txt
Script to get directory name out of DIR command output :
...
20/09/2014 01:23 [DIR] some1
21/09/2014 02:34 [DIR] some2
22/09/2014 03:45 [DIR] some3
23/09/2014 11:22 [DIR] some4
...
We want it to be:
some1
some2
some3
some4
...
Code :
#FOR /f "tokens=4" %%D IN (i:\test.txt) DO #( echo %%D ) >> result.txt
In your case tokens=3, not perfect but does the job with few lines manually edited in the result.
(For /f "tokens=3delims= " %%i in (ipports2.txt) do echo %%i) >ipports3.txt
should do it for you.
The paretheses are important - ensure that the file is created anew. If omitted, will only generate the last line.
Simply uses the delimiter [space] to tokenise the string on each line into token1=Port, token2=Name and sets %%i to each token3 in turn.
The following isn't really a different solution but merely a suggestion to simplify your script by reducing the number of output files.
In fact, it is possible to exclude all of them from the script, unless you need to keep them for history.
Basically, the idea is first to apply FINDSTR directly to the output of prnport.vbs:
CSCRIPT /nologo %windir%\System32\prnport.vbs -l | FINDSTR "IP_"
then apply a loop directly to the output of FINDSTR (note the single quotation marks around the piped command line, as well as the escaped |):
FOR /F "tokens=3" %%A IN (
'CSCRIPT /nologo %windir%\System32\prnport.vbs -l ^| FINDSTR "IP_"'
) DO …
and call prnport.vbs with another set of arguments in that same loop:
FOR /F "tokens=3" %%A IN (
'CSCRIPT /nologo %windir%\System32\prnport.vbs -l ^| FINDSTR "IP_"'
) DO (
CSCRIPT /nologo %windir%\System32\prnport.vbs -d -r %%A
)
The tokens option of a FOR /F loop specifies which token (or field) to take based on a specific delimiter or set of delimiters. The default set of delimiters is a space, a comma, a tab. Your Port name IP_whatever lines conveniently consist of exactly three tokens and the third one is what you are after, hence "tokens=3" in the options.
So, as you can see, no output files, the necessary value is extracted and passed to the target command in the same iteration.
So I want to create a script that takes 3 arguments: path to file, exact word to replace, and with what to replace it. How to create such thing?
Generally I want it to have an API like this:
script.bat "C:/myTextDoc.xml" "_WORD_TO_REPLACE_" "WordTo Use"
I have written something like 2 batch scripts in my life, but here's how to take input from the command line:
script.bat filepath find replace
%1 = filepath, %2 = find, %3 = replace
To do replacement, do something like:
for /f "tokens=1,* delims=]" %%A in ('"type %1|find /n /v """') do (
set "line=%%B"
if defined line (
call set "line=echo.%%line:%~2=%~3%%"
for /f "delims=" %%X in ('"echo."%%line%%""') do %%~X
) ELSE echo.
)
(taken directly from the link posted by #russ, with the variable numbers changed.)
I think this should work for you.
Use fnr utility its better than other famous utility since it can search and replace based on regular expressions. Also for the UI lovers you can configure options in UI and it can generate command line string which can then be used in your script. Very easy to use even as command line stirng.
Find it here http://findandreplace.codeplex.com/
Also it is single exe without any dependicies, so easy to use.
Example:
fnr --cl --dir "" --fileMask "hibernate.*" --useRegEx
--find "find_str_expression" --replace "replace_string"
A quick google search found this:
http://www.dostips.com/?t=Batch.FindAndReplace