I would like to extract what users are online based on this text file:
https://minecraft-statistic.net/en/server/167.114.43.185_25565/json/
I will save it as a text file. Inside that there is something:
"players_list":["Raskhol"]["Lukaka"],"map":...etc
I would like to extract all the text between "_list": and ,"map" and set it as a variable. So that when I call the variable %Playerlist%, it would say:
["Raskhol"]["Lukaka"]
similar to #geisterfurz007's answer, this one assumes the you are after the first instance of "players_list": before the first instance of ,"map"
#Echo Off
Set/P var=<some.json
Set var=%var:,"map"=&:%
Set var=%var:*"players_list":=%
Echo=%var%
Timeout -1
Not tested due to beeing on phone.
#echo off
For /f "delims=: tokens=2" %%g in (PathTo\file.txt) do (
Set var=%%g
Goto:next
)
:next
Set var=%var:,map=%
echo %var%
Assumes players are the first to be listed.
Reads the file, takes the part after the first : up to the second one, stores it in var.
Then ,map gets replaces with nothing to result in just the players beeing echoed in the end.
Feel free to ask questions if something is unclear! Might take a while as I am currently mobile though.
Related
I'm trying to create a batch file to insert a string from a .txt file at a specific place inside a string in 225 batch files - i.e., inserted into one line in the file at a specific place - but this question concerns the inserting part, and not the loop part, so I've left out the latter in my code example. It's also currently just displaying the text on-screen; not actually writing it to files.
The target files are a bunch of launch .bat files used for running a game server cluster using a tool, so I will have to leave each of them with the same names as they start with (Start XXYY.bat). They contain something along these lines:
start /high ShooterGame\Binaries\Win64\ShooterGameServer.exe Ocean?ServerX=0?ServerY=0?AltSaveDirectoryName=0000?ServerAdminPassword=1234?MaxPlayers=50?ReservedPlayerSlots=25?QueryPort=50002?Port=5002?SeamlessIP=192.168.1.225?RCONEnabled=true?RCONPort=28450 -log -server -NoBattlEye
exit
Where the ServerX, ServerY, AltSaveDirectoryNamen and all three Port settings are unique to each server, so these will have to remain unchanged.
I need to add several more settings, from another .txt file in the final version, but for this example I will just put the additions (the word INSERT added after the ReservedPlayerSlots setting, while keeping each setting divided by question marks) directly into this script.
My code is actually doing exactly what I want it to, but unfortunately it doesn't stop at that point, and decides to append more text than I wanted; specifically, everything I add to the ECHO command which is not a variable name.
To clarify, I get the exact output that I want... Plus the unwanted addition of a bunch of question marks and the word INSERT, which apparently come from my ECHO command, but I just have no idea why they get re-added.
My knowledge of batch scripting is fairly limited, so there might well be something basic that I've overlooked.
I've tried replacing the question marks in the output (which are required to be questions marks in the final version) with normal letters instead, but it doesn't change the behaviour; they were still appended to the expected output, just like the question marks they replaced.
#ECHO OFF
SET FileNum=0000
REM I will have the code loop through 225 files (0000-1414) in the final version, but for test purposes I just set it to one single file number manually here.
SET FileName=Start %FileNum%.bat
REN "%FileName%" temp.txt
FOR /F "tokens=1,2,3,4,5,6,7,8,9,10,11,12 delims=?" %%a IN (temp.txt) DO (
ECHO %%a?%%b?%%c?%%d?%%e?%%f?%%g?INSERT?%%h?%%i?%%j?%%k?%%l
)
REN temp.txt "%FileName%"
I expect this code to output this:
start /high ShooterGame\Binaries\Win64\ShooterGameServer.exe Ocean?ServerX=0?ServerY=0?AltSaveDirectoryName=0000?ServerAdminPassword=1234?MaxPlayers=50?ReservedPlayerSlots=25?INSERT?QueryPort=50002?Port=5002?SeamlessIP=192.168.1.225?RCONEnabled=true?RCONPort=28450 -log -server -NoBattlEye
exit
But what I am getting is this:
start /high ShooterGame\Binaries\Win64\ShooterGameServer.exe Ocean?ServerX=0?ServerY=0?AltSaveDirectoryName=0000?ServerAdminPassword=1234?MaxPlayers=50?ReservedPlayerSlots=25?INSERT?QueryPort=50002?Port=5002?SeamlessIP=192.168.1.225?RCONEnabled=true?RCONPort=28450 -log -server -NoBattlEye
exit???????INSERT?????
Which is the expected output, but with the unexpected re-addition of every symbol in the ECHO command which did not designate a variable at the end of the output (in this case ???????INSERT?????), just after the exit.
I'm stumped... I hope someone has an idea what I'm doing wrong here.
Okay, I applied the idea that aschipfl provided, and it seems to work now.
The IF NOT "%%b"=="" line seems to have done the trick, after I added the final line with the exit using another ECHO. My full script (including loop and write to file) is now like this:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
SET "Insert=SettingOne=True?SettingTwo=False?SettingThree=1.000000"
FOR /l %%x IN (0, 1, 14) DO (
FOR /l %%y IN (0, 1, 14) DO (
IF %%x LSS 10 (SET XNum=0%%x) ELSE (SET XNum=%%x)
IF %%y LSS 10 (SET YNum=0%%y) ELSE (SET Ynum=%%y)
SET "FileNum=!XNum!!YNum!"
SET "FileName=Start !FileNum!.bat"
ECHO Filename: !FileName!
REN "!FileName!" temp.txt
(
FOR /F "tokens=1-12 delims=?" %%a IN (temp.txt) DO (
IF NOT "%%b"=="" (
ECHO %%a?%%b?%%c?%%d?%%e?%%f?%%g?%Insert%?%%h?%%i?%%j?%%k?%%l
ECHO exit
)
)
) >edited.txt
REN edited.txt "!FileName!"
DEL /q temp.txt
ECHO has been updated
)
)
This is now working exactly as intended.
It's quite possible that there is a more elegant way of doing this, and I am cartain that there is a way of making this more general and less hard-coded, but it's good enough for my purposes.
I thank you for your help!
So in the batch script I'm building I am taking a single file from a folder, copying it over to a destination folder, and renaming it based on the number of times that the script has been looped. Essentially I need to take a file that's named the samething from a bunch of different folders spread across multiple computers at times and copy them into a new folder to work with. I've read up on xcopy and copy as that seemed like the thing to use but I haven't been able to find anything that lets me tell it to only copy over a single named file. I've posted what I have so far for the script below with commented lines for the sections I haven't figured out:
ECHO off
SETLOCAL enabledelayedexpansion
ECHO Note: Your combined permission list cvs can be found in the desktop folder
SET /A #=-1
:start
SET /A #+=1
:again
ECHO Please input the file path to the permissionoutput.txt
SET /p permissionoutputpath=
SET "sourcefolder=%permissionoutputpath%"
SET "destinationfolder=C:\Users\kayla\Desktop\HOLDER-CombinedPermissionsLists"
IF not exist "%sourcefolder%\permissionoutput.txt" Echo file not found&goto again
copy "%sourcefolder%\permissionoutput.txt" "%destinationfolder%\permissionoutput%#%.txt"
ECHO Add another file to combine: y or n?
SET /p addanotherfile=
if %addanotherfile%==y goto :start
UPDATE: Code corrected with answer to be fully functional for use as a reference
SET /A #=-1
:start
SET /A #+=1
:again
ECHO Please input the file path to the permissionoutput.txt
SET /p permissionoutputpath=
SET "sourcefolder=%permissionoutputpath%"
SET "destinationfolder=C:\Users\kayla\Desktop\HOLDER-CombinedPermissionsLists"
IF not exist "%sourcefolder%\permissionoutput.txt" Echo file not found&goto again
copy "%sourcefolder%\permissionoutput.txt" "%destinationfolder%\permissionoutput%#%.txt"
ECHO Add another file to combine: y or n?
SET /p addanotherfile=
if /i "%addanotherfile%"=="y" goto start
# is a legitimate variable-name. It's initialised to -1 then incremented on each loop through :start so the first value it will have when it's used is 0. (If you want to start at 1 just initialise it to 0 instead)
Next - your sets - BUT spaces are significant in a string set command are would be included in the variablename/value assigned if present in the set instruction. "quoting the assignment" ensures any stray trailing spaces on the line are not included in the value assigned.
Well - next, make sure the file exists and if it doesn't, then produce a message and loop back to :again which bypasses the increment of #.
Otherwise, simply copy the file. You're aware of its sourcename, and your destinationname is constructed by including %#% to include the current value of # (all batch variables without exception are strings - the set /a instruction merely converts from string to binary to perform the required calculation, then converts the result back to a string for storage in the environment.)
Finally, interpreting the request to add another file. if /i makes the comparison case-insensitive. Since you have no direct control over the user's response, "quoting each side" ensures the if syntax isn't violated in case the user enters "yup sure 'nuff" or some other unexpected response.
The leading colon is not required in a goto. I prefer to omit it to keep conguity with the call command where no-colon means an external routine will be called and a colon means the routine is in this batch file.
Ok so I am creating a script with a built in updater, it creates a new file with the following code and updates several variables, but for some reason this isn't working anyone have any idea how to fix it or a similar script that will do roughly the same thing.
#echo off
setlocal enabledelayedexpansion
set /p "findthis"="1"
set /p "replacewith"="1.2.3"
call:updater
set /p "findthis"="2"
set /p "replacewith"="2.3.4"
call:updater
set /p "findthis"="3"
set /p "replacewith"="3.4.5"
call:updater
goto:eof
:updater
for /f "tokens=*" %%a in (updateme.bat) do (
set write=%%a
if %%a==%findthis% set write=%replacewith%
echo !write!
echo !write! >>%~n1.replaced%~x1
)
goto:eof
there are several errors in this BAT.
Some are obvious syntax errors.
Read help set and correct all the set /p "this"="value" (hint: don't use /p option and correct the usage of " in the variable name)
you try to use %1 in a CALLed label. This is a passed parameter, and you are not passing it in your CALL. Read HELP CALL.
Some are logic errors.
The :updater code appends the updated string to the output file. It does so three times, so the final code is three times the original code with the strings changed.
Also, the code does try to find the string as a full line, a line containing just "1" in a BAT file does not make too much sense to me. You would probably want to find any text occurrence of "1".
Also, when you fix the previous problems, and if I understand correctly the intention of the code, you will eventually replace all "1" to "1.2.3" and then you replace all "2" to "2.3.4", so the original "1" will get replaced by "1.2.3.4.3".. and later on again, so it will finally be "1.2.3.4.5.4.3.4.5". Be careful with that.
How would I set a each line of a text document to separate variables using Batch? I know how to set a variable to the first line of a text document using:
Set /p Variable=<Test.txt
...but I don't know how to read other lines of the file. Lets say for example I had a text document with 3 lines, the first line had 'Apples' written on it, the second had 'Bananas' and the third had 'Pears', and lets say the document was called Fruit.txt. How would I set the variable 'Line_1' to the first line of the document, 'Line_2' to the second line and 'Line_3' to the last line?. Just to keep it simple, lets just say the batch file and Fruit.txt are both in the same folder. I don't want to do this in VBScript, so please only post Batch code. I would have thought that it would be something like:
#Echo off
Set /p Line_1=<Fruit.txt:1
Set /p Line_2=<Fruit.txt:2
Set /p Line_3=<Fruit.txt:3
Echo Fruit 1 is %Line_1%, Fruit 2 is %Line_2% and Fruit 3 is %Line_3%
Pause
Exit
...but quite clearly it isn't. Any help?
EDIT: This is for arbitrary-length files, then. jeb has an answer that solves your particular problem for a known number of lines. I will leave this here, though, as I hate deleting posts I put some time into for explanation :-)
Well, you obviously need some sort of counter. Let's start with 1:
set Counter=1
Then, you need to go line-wise through the file:
for /f %%x in (somefile) do ...
Then store the line in a numbered variable (that's what we have the counter for):
set "Line_!Counter!=%%x"
aaaaand increment the counter:
set /a Counter+=1
And that's it. Add a few more necessary things, you know, the boring stuff that's always needed in such cases (strange statements before and after, block delimiters, etc.), and you're done:
#echo off
setlocal enabledelayedexpansion
set Counter=1
for /f %%x in (somefile) do (
set "Line_!Counter!=%%x"
set /a Counter+=1
)
set /a NumLines=Counter - 1
Echo Fruit 1 is %Line_1%, Fruit 2 is %Line_2% and Fruit 3 is %Line_3%
rem or, for arbitrary file lengths:
for /l %%x in (1,1,%NumLines%) do echo Fruit %%x is !Line_%%x!
Some explanation:
set /p Var=<file will set the variable to the first line of a file, as you noted. That works because set /p will prompt for input and < file will redirect the file into standard input of a command. Thus set /p will interpret the file's contents as the entered input up until the user hits Return (i.e. the file contains a line break). That's why you get the first line. The system would throw the whole file at set /p but since the command only reads the first line and then is done they just get discarded.
The syntax you were proposing there is actually for accessing Alternate Data Streams of files on NTFS, which is somethhing totally different.
<short-detour> However, jeb has a way of reading multiple lines. This works because the block (delimited by parentheses) is a single command (see below) you can redirect a file's contents into. Except that command is comprised of multiple statements, each of which will read a single line and store it away. </short-detour>
Which brings us to for /f which iterates over the contents of a file (or the output of a command) line by line and executes a command or block of commands for each line. We can now read the whole file into as many variables as there are lines. We don't even need to know how many in advance.
You may have noticed the Line_!Counter! in there which uses Counter a little bit differently from how you're used to use environment variables, I guess. This is called delayed expansion and is necessary in some cases due to how cmd parses and executes batch files. Environment variables in a command are expanded to their values upon parsing that command. In this case the whole for /f including the block containing two statements is a single command for cmd. So if we used %Counter% it would be replaced by the value Counter had before the loop (1) and never change while the loop is running (as it is parsed once and run multiple times. Delayed expansion (signaled by using ! instead of % for variable access changes that and expands environment variables just prior to running a command.
This is almost always necessary if you change a variable within a loop and use it within the same loop again. Also this makes it necessary to first enable delayed expansion which is done with the setlocal command and an appropriate argument:
setlocal enabledelayedexpansion
set /a will perform arithmetic. We use it here to increment Counter by one for each line read.
To read multiple lines with set/p you need brackets around the set/p block.
#Echo off
(
Set /p Line_1=
Set /p Line_2=
Set /p Line_3=
) <Fruit.txt
Echo Fruit 1 is %Line_1%, Fruit 2 is %Line_2% and Fruit 3 is %Line_3%
I am writing a batch file (I asked a question on SU) to iterate over terminal servers searching for a specific user. So, I got the basic start of what I'm trying to do.
Enter a user name
Iterate terminal servers
Display servers where user is found (they can be found on multiple servers now and again depending on how the connection is lost)
Display a menu of options
Iterating terminal servers I have:
for /f "tokens=1" %%Q in ('query termserver') do (set __TermServers.%%Q)
Now, I am getting the error...
Environment variable __TermServers.SERVER1 not defined
...for each of the terminal servers. This is really the only thing in my batch file at this point. Any idea on why this error is occurring? Obviously, the variable is not defined, but I understood the SET command to do just that.
I'm also thinking that in order to continue working on the iteration (each terminal server), I will need to do something like:
:Search
for /f "tokens=1" %%Q in ('query termserver') do (call Process)
goto Break
:Process
for /f "tokens=1" %%U in ('query user %%username%% /server:%%Q') do (set __UserConnection = %%C)
goto Search
However, there are 2 things that bug me about this:
Is the %%Q value still alive when calling Process?
When I goto Search, will the for-loop be starting over?
I'm doing this with the tools I have at my disposal, so as much as I'd like to hear about PowerShell and other ways to do this, it would be futile. I have notepad and that's it.
Note: I would continue this line of questions on SuperUser, except that it seems to be getting more into programming specifics.
Ok, those are quite a few questions/issues/etc. in one :-)
And I still don't quite get where exactly you're headed with that script.
First of all, the syntax for the set command is
set <variable name>=<value>
If you do just
set <variable name>
then it will list all environment variables starting with <variable name>. If there are none, then it will output the error message you're seeing.
If you want to define a variable without actually caring about its value, you still need to provide a value. I usually use 1 for such flags, since it's then more an on/off switch than an actual variable holding a value:
set Foo=1
In your case you probably want something else, though. There are no arrays per se in batch files, you can mimic them by creating a number of variables and holding a count somewhere. I've written about that once before (a little outdated by now, but still valid).
In your case you want to iterate over a number of servers and for each server over a number of users. You can do that with a nested loop:
for /f "tokens=1" %%Q in ('query termserver') do (
for /f "tokens=1" %%U in ('query user ... /server:%%Q' do (
...
)
)
As for your two questions there:
No, the loop variable is only valid inside the loop, not when calling a subroutine. You can pass it to the subroutine, however:
for ... in (...) do call Process %%Q
You can then access it with %1 in the subroutine. Honestly, though, in most cases I think the nested loops are easier to read.
Yes.
Another error (one that will bite you): As mentioned before, the set syntax is
set variable=value
Note that there is no space around the = sign. If there is, then you have a space at the end of the variable name or at the start of the value:
> set foo = bar
> echo %foo%
%foo%
> echo %foo %
bar