DOS batch command to read some info from text file - command-line

I am trying to read some info from a text file by using windows command line, and save it to a variable just like "set info =1234"
Below is the content of the txt file, actually I just need the revision number, and the location of it is always the same line 5, and from column 11 to 15. In the sample it's 1234, and I am wondering is there a way to save it to a variable in Dos command line.
Thanks a lot!
svninfo.txt:
Path: .
URL: https://www.abc.com
Repository Root: https://www.abc.com/svn
Repository UUID: 12345678-8b61-fa43-97dc-123456789
Revision: 1234
Node Kind: directory
Schedule: normal
Last Changed Author: abc
Last Changed Rev: 1234
Last Changed Date: 2010-04-01 18:19:54 -0700 (Thu, 01 Apr 2010)

Here's a one line version:
for /f "tokens=2" %%i in ('findstr Revision: input.txt') do set revision=%%i
findstr is used to filter the file. It will print "input.txt:Revision: 1234"
Then the "tokens=2" means that we are interested in the second token, "1234". By default for breaks on white space.

The following code snippet shows how to do this:
#echo off
setlocal enableextensions enabledelayedexpansion
set revision=
for /f "delims=" %%a in (input.txt) do (
set line=%%a
if "x!line:~0,10!"=="xRevision: " (
set revision=!line:~10!
)
)
echo !revision!
endlocal
Its output is 1234 as desired.
The setlocal is what I use in every script to ensure variables are treated in a known way. The for statement processes each line in the input file (the delims bit stops the line from being tokenised into separate words).
The !line:~ bits are substrings with !line:~0,10! being the first ten characters and !line:~10! being the rest.
So, basically, it checks every line to see if it starts with "Revision: " and, if so, extracts the rest of the line for later.

Use the for command to parse the file:
for /f "skip=4 tokens=2" %%l in (svninfo.txt) do (
set revision=%%l
goto gotrev
)
:gotrev
echo revision is %revision%

if you have can use GNU tools, such as gawk
#echo off
for /F %%a in ('gawk -F":" "$1~/Revision/{print $2}" file') do (
set var=%%a
)
echo %var%

Knowing how to use CMD scripting deftly is great, but using PowerShell is even better. Here's one way to do it:
$revision = (( gc .\svninfo.txt | ? { $_.StartsWith( 'Revision: ' ) } ) -split ' ')[1]
What's going on?
$revision is a variable
gc is Get-Content, aka type. Each line in the file becomes a string in a sequence (pipeline).
? is Where-Object. It filters the objects in a pipeline based on a condition.
{} delimits a script block
$_ is the current object in the pipeline.
-split invokes String.Split() in .NET, giving you an array of objects
[1] indexes in to the array

Related

Powershell in Batch file: Errors and Commands not executing

Below you can find the content of the two example text files I will use, example1.txt and obf_example1.txt. The latter one contains the string of example1.txt at the end of the file but has some obfuscated strings before.
example1.txt:
adasdkasdaksdasdkjlasdjasndjasd.
obf_example1.txt:
ŠxpÃÒ²Ø-Gêÿ ój"f>ïí H€À(ø4$/+#6Ni9Pvü¶ |CF CÀ¾ý~ª-°à9ÉOÿ V[o¦.E…-Š ƒ9Ú\žê*D´ß()^“£¹ìÅjXÑÍ¥â(¨µ×d'«P|I*èSººº&)Ø|̉ òÔ®¥Ô$LÁ:9ŠLá{¶nZÒبNÙÀØŒ‹0õ´Sék›áÇÉîÆbËF§BЄƒöZKaÒR ²°ÅšDn?+¶()IªP›$ÇEv©¡k€[ßè¨×q-Ëk!µTóPA²—: A ?ÉEEEGÐJúÌ©ÒWµHB¡aäXû|ÓË BPÁwr„Ûi¥åܺÈQ÷ORàSb,Šv¢D ,Žb’(2 öb¢wtKzíĦ#ï¯u©²Ù aîR隬ëÌTbà÷¥3ÄtSGì´R$)X Šù
'¹¨D³ÞeOK3!{·‹¦cäиNÅô:Na1žAÇ1ø8 &Fuôë %¸T¯_òMå†C"ý¤F ™º„Iµºí4Ü¡ˆc!ì•+3 ‰‹M K#JÁ«8¢bsL†!Ù“à­šn·öMå•Œ&ýèvÀ}¨?¦hùÊò(É#Žf~5‰‘qØçþƒ‰Å²ÓÖÊJU•âNWÁ«L¼Y”$G¢ßè&§ÖÉØŒS‘WàË„°SØW Ð¨´_è%‚Å¢ø.ãÃð”#X^þ*1þ‚q85¡lÒ‚Ò>‘¸ÿ £ôQôz#ø¤ÎõÚªï|Xö%;åÍËûGú+îUƒö³‰›p U±Ò ðtÜGÜÿ  ð,åXÿ k8È I”ÿ “½¿Ð`¨u5=SÓqyFÈ É8ôã¨ð£è6’H#lÄI10‚Ö§ÑdµÖ?t¡]D†9Zj,¥EɺÜEq¤#,ìn—¢º‚´€bc·ú¨Lû£ÿ Ó×ÿÙ||adasdkasdaksdasdkjlasdjasndjasd.
When I ran the following powershell command for example.txt in a batch file, it works and I get the output of example.txt:
#echo off
for /f "delims=" %%a in ('powershell Get-Content .\example.txt') do set _output=%%a
echo %_output%
adasdkasdaksdasdkjlasdjasndjasd
Good so far.
However, when I ran the above powershell command for obf_example1.txt, it does not work and I get the following error message:
'¹¨D³ÃzeOK3!{·â?¹Â¦cäÃ?Â?¸Â?NÃ.ô:Na1žAÃ╬1ø8
The command "FuôëÂ" is either misspelled or could not be found.
The command "ýèvÃ?}¨?¦hùÃSÂ?ò" is either misspelled or could not be found.
Why? Never mind I thought: As I am only interested in the last n characters both in example1.txt and obf_example1.txt accordingly, my idea was to extract the last n characters and check if I can see the output of obf_example1.txt then. To check if my idea works, I run the following command for example1.txt to get the last 4 characters as an example:
#echo off
for /f "delims=" %%a in ('powershell $a=Get-Content .\example.txt; $a.substring^(0,$a.length-4^)') do set _output=%%a
echo.%_output%
It doesn't show me anything though. %_output% seems to be empty. How to fix that? And will the fixed version work for obf_example1.txt as well so that I get an output there instead of the above error message?
Apparently, the piece of text you are after is behind the ||.
With PowerShell you can easily get that by using
((Get-Content 'D:\Test\obf_example1.txt' -Raw) -split '\|\|')[-1]
Returns
adasdkasdaksdasdkjlasdjasndjasd
Isn't htis what you want?
You could try reading the last 4 bytes, if you really are taking text characters from what is clearly not a text file. (My guess is that it is text hidden inside a binary file, probably a graphic file).
#For /F Delims^=^ EOL^= %%G In (
'%__AppDir__%WindowsPowerShell\v1.0\powershell.exe -NoP^
"$f=[IO.File]::OpenRead('C:\Users\Ferit\Desktop\obf_example1.txt');"^
"$f.Seek(-4,[System.IO.SeekOrigin]::End)|Out-Null;$buffer=new-object Byte[] 4;"^
"$f.Read($buffer,0,4)|Out-Null;$f.Close();"^
"[System.Text.Encoding]::UTF8.GetString($buffer)"')Do #Set "_output=%%G"
#Set _output 2>NUL&&Pause
Don't forget to modify the text file path, (on line 3), and the three instances of 4 if you want more or less bytes. The last line is included just to show you the output, (you would obviously replace that with your own code).
The following works for me to get the "clear-text" part after || (from your example):
for /f "delims=" %%a in (.\obf_example1.txt) do set "_output=%%a"
set _output
echo testing last 10: %_output:~-10%
set "_output=%_output:*||=%"
set _output
echo %_output%
(it might not work with different encodings of the text file)
(Consider Powershell - cmd has a limit on line length and can easily be overwhelmed)

batch file to open txt replace text save and close

I understand that this community is for helping people and I'm not one hundred percent how to ask for someone to do a commissioned job or w/e but I'd like a series of batch files for changing certain numbers to a particular number per batch file.
echo off
if exist %application.yml del %application.yml
for /F "delims=" %%l in (%1) do (
set "line=%%l"
set "line=%line:specific text=another word%"
echo/%line%>> %application.yml)'
How would I set this to replace an array of numbers to the set number, I'm sorry I'm a complete idiot with this.
File itself application.yml
product:
# Cntrl alt 1 Mini, 2 m16, 3 scar, 4 m4169, 5 akm, 6 ump,7 sks
discordUsername:
discordPassword:
maxCPUsUsage: 4
shutdownKey: 0x7B
reloadConfigKey: 0x79
screenResolutionX: 1920
screenResolutionY: 1080
playerEsp: true
playerEspColor: 0xFF00FF
playerEspPointSize: 1
radarEsp: true
radarEspColor: 0x0000FF
radarEspPointSize: 2
vehicleEsp: true
vehicleEspColor: 0xff0000
vehicleEspPointSize: 1
vehicleEspHotkey: 0x2D
lootEsp: true
lootEspColor: 0x00FF00
lootAirdropEspColor: 0xffffff
lootEspPointSize: 1
lootEspHotkey: 0x24
redrawTime: 0
reloadDataTime: 2000
aimEnabled: true
aimKey: 0x39
aimFOV: 95
aimFrequency: 6
aimPrecision: 1
aimSpeed: 1
bulletSpeed: 990
aimHitbox: 0
# Key list: https://msdn.microsoft.com/en-us/en-en/library/windows/desktop/dd375731(v=vs.85).aspx
So essentially the number I wish to replace is the bullet speed and it could be multiple numbers from previous changes ect, for example
990
870
400
and if it is any of these instances I wish to replace it with
900
and so on and so forth.
So it searches for any of the possible numbers and changes it to the specified number and save the file under the same file name.
Thanks in advance for any help if I'm being completely honest in the example I dont even know what to change to make it simply replace one number to the other never mind multiple instance searches :)
Once again ty for any advice or help.
The following commented .bat script should do the job, although empty lines are not copied to output file:
#ECHO OFF
SETLOCAL EnableExtensions
rem redirect all output to a brand new file
>application.yml (
rem parse a file (supplied file name %1 must not be equal to "application.yml")
for /F "usebackq delims=" %%l in ("%~1") do (
rem parse each line
for /F "tokens=1* delims=:" %%L in ("%%~l") do (
if /I "%%~L"=="bulletSpeed" (
rem modified line
echo(%%L: 900
) else (
rem original line
echo(%%l
)
)
)
)
BTW, in the original script, you would need Delayed Expansion to make proper reference to variables (re)defined within a parenthesised code block (like a FOR loop body), e.g. as follows:
echo off
SETLOCAL EnableExtensions EnableDelayedExpansion
if exist application.yml del application.yml
for /F "delims=" %%l in (%1) do (
set "line=%%l"
set "line=!line:specific text=another word!"
echo/!line!>>application.yml
)
Resources (required reading):
(command reference) An A-Z Index of the Windows CMD command line
(helpful particularities) Windows CMD Shell Command Line Syntax
(%~L etc. special page) Command Line arguments (Parameters)
(special page) EnableDelayedExpansion
(>>, > etc. special page) Redirection
Regular Expressions are ideal to do this sort of editing.
Aside from findstr's limited capabilities batch is lacking RE support.
This wrapped powershell one liner will do the job either on cmd line or in a batch-file.
powershell -NoP -C "(gc application.yml) -Replace '(?<=bulletSpeed: )\d+','900'|sc application.yml"
It uses a lookbehind assertion to replace any number following bulletSpeed: with 900.
To limit the replacement to one of previous 990, 870, 400 use this:
powershell -NoP -C "(gc application.yml) -Replace '(?<=bulletSpeed: )(990|870|400)','900'|sc application.yml"

Use Variable insted of Get-Date in powershell

I am using PowerShell "(Get-Date).AddDays(-7).ToString('ddMMyyyy')" in batch script.
I want to use a variable instead of Get-Date function. Is it possible?
ADate is the variable name!
Edited:
As suggested, my script is:
For /F UseBackQ %%A In (
`PowerShell "(Get-Date).AddDays(-7).ToString('ddMMyyyy')"`
) Do Set "Freq=%%A"
Adate is simple string which comes from the file name, and has a value like 16112016.
You need to use a for loop to get the output of an external command in a batch variable:
#echo off
for /f "usebackq tokens=*" %%d in (`powershell "..."`) do set "adate=%%d"
echo %adate%
The usebackq and backticks are just so you don't need to escape the nested single quotes in your command string.
Ok. I got my crystal ball and asked it: "What is the solution here?", and it replied: "Change
PowerShell "(Get-Date).AddDays(-7).ToString('ddMMyyyy')"
by
PowerShell "(Get-Date -Date '!Adate:~4!-!Adate:~2,2!-!Adate:~0,2!').AddDays(-7).ToString('ddMMyyyy')"
", but I have no idea what it is talking about! ;)
You can store the output of the powerShell command into a file and then read that file after that delete that temporary file.
PowerShell "(Get-Date).AddDays(-7).ToString('ddMMyyyy')" >temp.txt
set /p myVarDate= < date_Shell.txt
echo Date from Shell %myVarDate%
del temp.txt
The following takes the last modified time from a known file's properties and creates a variable with a date seven days earlier, (obviously changing C:\Test\TestFile.ext as necessary):
For /F UseBackQ %%A In (
`PowerShell "((gi 'C:\Test\TestFile.ext').LastWriteTime).AddDays(-7).ToString('ddMMyyyy')"`
) Do Set "ADate=%%A"
Edit
The following example takes a date string with a known format, (in this case provided in two variables). It then converts that string to a date object, subtracts seven days and sets it back to a string in the new %ADate% variable:
#Echo Off
Set "DateStr=16112016"
Set "DFormat=ddMMyyyy"
For /F UseBackQ %%A In (`Powershell^
"([datetime]::ParseExact('%DateStr%','%DFormat%', [System.Globalization.CultureInfo]::CurrentCulture)).AddDays(-7).ToString('%DFormat%')"
`) Do Set "ADate=%%A"
Echo(%ADate%
Timeout -1

Remove Carriage Return from String Field in File Windows Command Line

I have a file that is ouput with | as the delimiter. However, one of the fields is a description field from the source system which contains carriage returns. This is an issue when trying to read the file as it breaks it on to a new line. What I would like to do is remove all CF/LF that aren't preceeded by a |.
I feel like this should be possible on command line but haven't been able to come up with it.
Sample data
|A|Testing CF/LF
This|CF/LF
Expected Output
|A|Testing This|CF/LF
#ECHO Off
SETLOCAL
SET "line="
(
FOR /f "delims=" %%a IN (q26895698.txt) DO (
CALL :generate "%%a"
)
)>newfile.txt
TYPE newfile.txt
GOTO :EOF
:generate
SET "line=%line%%~1"
IF "%line:~-1%"=="|" SET "line="&FOR %%x IN ("%line%") DO ECHO(%%~x
GOTO :eof
I used a file named q26895698.txt containing your data (such as it was) for my testing.
Produces newfile.txt
Can't help but get the impression that you'd be better off with SED thouh - google "GNU SED" for details...

how to rename files using command line

I want to rename 2 files "Data1.txt" to "Log1.rtf" and "Data2.txt" to "Log2.rtf"
I am currently using this code
#ECHO OFF
FOR %%I IN ("%~dp0*.txt") DO (
SET "ext=%%~xI"
SETLOCAL EnableDelayedExpansion
RENAME "%%I" "%%~nI!Log.rtf"
ENDLOCAL
)
But it give output "data1log.rtf" and "data2log.rtf"
of course:
RENAME "%%I" "%%~nI!Log.rtf"
But it give output data1log.rtf and data2log.rtf
btw. what do you try to achive with setlocal delayedexpansion and that single ! ?
EDIT: if you insist in doing it with for (because perhaps, you have many files to rename):
#echo off
setlocal enabledelayedexpansion
for %%i in (*.txt) do (
set file=%%i
set file=!file:Data=Log!
set file=!file:.txt=.rtf!
echo ren %%i !file!
)
the first set sets the variable file to the filename
the second one replaces Data with Log
the third one replaces .txt with .rtf
then rename original filename (%%i) to the changed filename (!file!)
(the echo is there to just show the command on screen instead of really renaming files. Good for testing. If you are sure, that the code does, what you want, just remove the echo)
the setlocal enabledelayedexpansion is needed to use a variable, that is changed inside a block (between ( and )) inside the same block. Therefore you have to use the variable as !var! instead of %var%
Note: of course this code could be improved, but as a beginner: keep it as simple (and readable) as possible. For example, this code will replace Data, but not data or DATA, it will not handle spaces in filenames, ...
It might work better if you used separate code to rename each of the files, or does that defeat the object?
this website shows how to rename a file using command line:
http://www.sevenforums.com/tutorials/56013-file-folder-rename-command-prompt.html
for %%a in ("%~dp0data*.txt"
) do for /f "delims=DdAaTt" %%b in ("%%~na"
) do echo ren "%%~fa" "log%%b.rtf"
It just iterates over the indicated list of files, and for each filename, uses the unnecesary characters as delimiters for an aditional for loop. That way only the number is left and used to rename the file.
Commands to rename are echoed to console. If output is correct, remove the echo command to rename the files.
User mv command to rename files in windows (Using CLI)
As mentioned in above answer, mv command can be used in windows as well to rename the filename. I tried rename and ren commands s suggested, but I was getting error: bash: ren: command not found.
Use below to change the filename:
mv filename new_filename