saving output as variable - windows

I am working on a batch script and am trying to save part of the output of a command as a variable. My current script requires the user to enter a site code (e.g. 853), and it takes that code and uses it to query a sql database. The command I'm using is as follows:
sqlcmd -S"localhost\SQLONESOURCE" -Uusername -Pmypassword -dOneSource -Q"select AdmSiteID from [10.33.144.114].onesource.dbo.admsites where siteid='%sitecode%'"
When this command runs, I get the following output:
AdmSiteID------------------------------------
AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE
(1 rows affected)
I just want to take the AdmSiteID (AAAAAAAA-BBBB-CCCC-DDDD-EEEEEEEEEEEE) and save that as a variable. It will always be in that format with the same number of characters and dashes.

This batch code get the third line from your sqlcmd output:
for /F "skip=2" %%a in ('sqlcmd -S"localhost\SQLONESOURCE" -Uusername -Pmypassword -dOneSource -Q"select AdmSiteID from [10.33.144.114].onesource.dbo.admsites where siteid='%sitecode%'"') do (
set thirdLine=%%a
goto continue
)
:continue
echo %thirdLine%

The first thing to do is to ensure your SQLCMD output includes some sort of unique text that you can search for. For example, you could modify your query as follows:
"select 'FOO~' + AdmSiteID + '~' from [10.33.144.114].onesource.dbo.admsites where siteid='%sitecode%'"
Then write your SQLCMD output to a file by adding -o %OUTPUT_FILE% to your SQLCMD.EXE line, where %OUTPUT_FILE% has already been defined.
Then use a combination of for and findstr.exe to pull your file apart:
for /f "tokens=2 delims=~" %%D in ('%SystemRoot%\System32\findstr.exe /l /c:"FOO~" %OUTPUT_FILE%') do set YOUR_VARIABLE=%%D
This hasn't been tested, but I know the theory is sound. If it doesn't work, and you're struggling to fix it, let me know, and I'll spend more time on it.

Related

Reading parameter inputs from a txt/csv file to run a command in loop (windows batch)

Kindly excuse me if it seems a bit amateur. I'm not so good with windows batch files.
I am using Instaloader to download single posts. Instaloader can take an input with a content ID. I am trying to write a batch file so that it can take content IDs as an input from a csv file and download it in a loop.
Here is my sample which works but I have to input an ID every time. I would like it to take the ID from a csv file until it finishes all the rows.
#echo off
:prompt
set /p post= "Enter ID: "
instaloader --no-metadata-json --no-compress-json --no-captions --dirname-pattern={profile} --filename-pattern {profile}_{date_utc} -- -%post%
echo.
goto prompt
I should use FOR I believe but I just couldn't get it work. Thanks for any suggestions.
I tried a few samples of using FOR but it just fails. I am not sure if there is a better approach to this. I don't mind using powershell if it can be done in a more efficient way like using Import-CSV first.
The PS attempt:
foreach ($post in Get-Content '.\IG Posts.txt')
{
do { instaloader --no-metadata-json --no-compress-json --no-captions --dirname-pattern={profile} --filename-pattern {profile}_{date_utc} -- -$post } while (eol)
}
Sample txt/csv (they are actual content IDs that instaloader would download:
Cm4AoMVy60x
Cm0UMTAyLJe
ClViwoRStoa
[Theoretical and untried]
#echo off
setlocal
if "%~1"=="" echo Syntax %0 "filename containing list"&goto :eof
for /f "usebackq delims=" %%b in ("%~1") do instaloader --no-metadata-json --no-compress-json --no-captions --dirname-pattern={profile} --filename-pattern {profile}_{date_utc} -- -%%b
goto :eof
where this batch should be invoked as thisbatch "filename"
%1 is the first parameter on the command line. %~1 is the same, minus any enclosing quotes. "%~1" is the (first paramater - enclosing quotes) enclosed in quotes.
In the for /f line, the usebackq means "the thing in quotes is a filename" and delims= means "there are no delimiters on the lines of the file".
So each line of the files is assigned to %%b in turn and instaloader is run using the contents of the line.
Note that if instaloader is a batch file, you should use call instaloader...
I'm assuming a textfile contains the required data, one to a line. If you want otherwise, please post a sample.

Batch file variable filenames: make timestamp filename within a for loop?

I am trying to run a batch of Lighthouse audits from the command line and output the results to JSON files. To ensure they don't overwrite one another, each file name needs to be unique. I would like to use the timestamp as the filename ideally. I have been through many other Stack questions on a similar topic, but I cannot get this to work. I am currently using the below code, written within a batch file and called from Windows command line:
SETLOCAL ENABLEDELAYEDEXPANSION
for /f "delims=" %%a in (C:\Users\User\Desktop\Folder\Lighthouse_Project\urls.txt) DO (
set dte=!DATE:/=-%!
set tme=!TIME::=-%!
set tme=!%tme:.=-%!
ECHO Line is: %%a
lighthouse %%a --quiet --chrome-flags=" --headless" --output=json --output-path=C:\Users\User\Desktop\Folder\Lighthouse_Project\json_logs\!dte!!tme!.json
)
The first file produced has the correct name all subsequent JSONs have the literal name: '!dte!!tme!', and do overwrite one another. If you run the Lighthouse command outside of a for loop it executes perfectly, I'm aware that variables don't update within a for loop but I thought !var! could be used to counter this. The for loop iterates through a list of URLs stored in urls.txt, auditing each of them in turn and returning a JSON file.
Current outcome: !dte!!tme!.json
Desired oucome: 08-10-201913-55-12-07.json, 08-10-201913-56-14-00.json etc.
If anybody knows how to amend this to achieve the correct outcome I would be very grateful.
The urls.txt contains a list of URLs, each on a new line:
https://www.bbc.co.uk/weather/2643743
https://www.bbc.com/mundo
https://regex101.com/
https://www.bbc.co.uk/news
Example:
#Echo Off
SETLOCAL ENABLEDELAYEDEXPANSION
for /f "delims=" %%a in (C:\Users\Owner\Desktop\Folder\Lighthouse_Project\urls.txt) DO (
set dte=!DATE:/=-!
set tme=!TIME::=-!
set tme=!tme:.=-!
ECHO Line is: %%a
echo lighthouse "%%a" --quiet --chrome-flags="--headless" --output=json --output-path="C:\Users\Owner\Desktop\Folder\Lighthouse_Project\json_logs\!dte!!tme!.json"
Timeout 2 >NUL
)
Timeout -1 >NUL
This uses the exact content from your urls.txt example. I have added #Echo Off at the top to reduce screen clutter, and an echo in front of your lighthouse command so that it displays instead of runs. Additionally I included a couple of timeouts to both simulate a short timespan, (as the command is being echo'ed not ran), and to give you an opportunity to read the output at the end.
Here's the output from the above to prove my case:
Line is: https://www.bbc.co.uk/weather/2643743
lighthouse "https://www.bbc.co.uk/weather/2643743" --quiet --chrome-flags="--hea
dless" --output=json --output-path="C:\Users\Owner\Desktop\Folder\Lighthouse_Pro
ject\json_logs\08-10-201916-12-42-93.json"
Line is: https://www.bbc.com/mundo
lighthouse "https://www.bbc.com/mundo" --quiet --chrome-flags="--headless" --out
put=json --output-path="C:\Users\Owner\Desktop\Folder\Lighthouse_Project\json_lo
gs\08-10-201916-12-44-14.json"
Line is: https://regex101.com/
lighthouse "https://regex101.com/" --quiet --chrome-flags="--headless" --output=
json --output-path="C:\Users\Owner\Desktop\Folder\Lighthouse_Project\json_logs\0
8-10-201916-12-46-12.json"
Line is: https://www.bbc.co.uk/news
lighthouse "https://www.bbc.co.uk/news" --quiet --chrome-flags="--headless" --ou
tput=json --output-path="C:\Users\Owner\Desktop\Folder\Lighthouse_Project\json_l
ogs\08-10-201916-12-48-21.json"
Press any key to continue . . .
Your issue, as originally stated, was the inclusion of % characters in your initial set syntax, as you can see from the provided output.
By keeping the expansion without exiting the loop as you intended.. Note I have added a timeout of millisecond here to ensure we have a different time each time. ping 127.0.0.1 -n 1 -w 500> nul:
#echo off
setlocal enabledelayedexpansion
for /f "delims=" %%a in (%userprofile%\Desktop\Croud_DS_1\Lighthouse_Project\urls.txt) DO (
set dte=!date:/=-!
set tme=!time::=-!
set tme=!tme:.=-!
set tme=!tme:,=-!
echo Line is: %%a
lighthouse "%%a" --quiet --chrome-flags=" --headless" --output=json --output-path=%userprofile%\Desktop\Folder\Lighthouse_Project\json_logs\!dte!_!tme!.json
ping 127.0.0.1 -n 1 -w 500> nul
)
Please take note, I took the liberty of adding an underscore to make sure the date and time format is readable, so you'll have YYYY-MM-dd_HH-mm-ss-ms

wget: batch download with increment

I have this situation: I want to download a bunch of files named like this:
683482, 684483, 685484, 686485, 687486, 688487, 689488, 690489, 691490, 692491, ...
As you can see, the files are numbered with an increment of 1001. So, what's the easiest way to do a batch download?
Please try this:
#!/bin/bash
for i in {683482..1000000..1001}
do
wget $i
done
ECHO OFF
CLS
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /L %%A IN (683482,1001, 692491) DO (
SET stringWget=wget %%A
!stringWget!
)
I'll go step by step:
ECHO OFF prevents windows command line from displaying every command on the command-prompt (this is optional; But, looks clean).
CLS clear screen; This clears command prompt's console display. It does not clear the temporary environment variables or command history.
SETLOCAL ENABLEDELAYEDEXPANSION is used for non-blocking statements and is Windows specific; When we use %ENVIRONMENTVARIABLE% , we are implying blocking statement and when we use !ENVIRONMENTVARIABLE! we are implying non-blocking statement (meaning, in a loop, we see updated values of %A instead of repeating what %A had when entering loop). We use %% instead of %in batch files.
FOR loop's syntax can be found in reference.
Reference: https://stackoverflow.com/a/3541415

Running a command on every file in a folder, then saving output

I am new to writing batch scripts and was hoping for some help.
I have a folder of images. I want to cURL each of these images, one by one, to an image classifier I made on the web. This will then send me a result.
I then want to save the response of the server into a file - let's keep it simple a say a CSV, in this format:
File, Response
So I know to run the Batch on each folder, I can do the following -
for /f %%f in ('dir /b c:\') do echo curl -X POST -F "images_file=#%%f" "https://gateway-a.watsonplatform.net/visual-recognition/api/v3/classify?api_key=abcdefgh&version=2016-05-20"*
I know, I can somehow pipe the results into an output file using ">>".
I don't know how to put this together, and how to create the CSV as I am running the batch script. Can anyone help? I think I am 90% there just new to batch scripting.
You can do something like this in powershell :
Change the placeholders as per your requirement.
$dir_files=Get-ChildItem "C:\"
foreach($file in $dir_files)
{
$result=Invoke-WebRequest 'https://gateway-a.watsonplatform.net/visual-recognition/api/v3/classify?api_key=abcdefgh&version=2016-05-20' -Method Post -Headers 'images_file=#%%f'
$result | ConvertTo-Csv | Out-File "D:\outputfile.csv" -Append -Force
}
I just gave you the way to set off. I didn't go through the complete batch code.
Hope it helps you.
If you want to use batch, you can do:
#echo
SetLocal EnableDelayedExpansion
set imagedir=C:\
set csvfile="C:\results.csv"
FOR %%G IN ("%imagedir%*") DO (
set resultfile=%%G.out
echo curl -X POST -F "images_file=#%%G" "https://gateway-a.watsonplatform.net/visual-recognition/api/v3/classify?api_key=abcdefgh&version=2016-05-20"* -o "!resultfile!"
echo %%G, !resultfile! >> %csvfile%
)
EndLocal
exit /b 0
I am not that experienced with curl so I'm not able to verify the correctness of your curl command and let the echo before it. But I do know that you can actually specify a file to write the output to in Windows with the -o flag.
The FOR command (without any flag/option) is another way to loop through files in a directory. If you still want to use the for /f %%f in ('dir /b ...') do-style (perhaps because of the order in which you want to treat your images), you can simply replace the line FOR %%G IN ("%imagedir%*") DO ( with for /f %%f in ('dir /b "%imagedir%"') DO (. I saved the directory in the variable imagedir, it's then easier to change. But if you change it, don't forget the \ at the end (if you use my for-command) and don't add double quotes (I add them in the FOR command). Be aware that this will treat all FILES in the directory. You can specify extensions if you want by using "%imagedir%\*.jpg" "%imagedir%\*.gif" for example for only GIF and JPEG images.
As last I'll say that I added SetLocal EnableDelayedExpansion to use delayed expansion. It's actually only needed because I saved the name of the file where the result of the curl operation will be saved, in the variable resultfile. In batch, a FOR -block (FOR ... ( ... )), and other blocks delimited with ( ) (as IF-blocks), are parsed as one single command (as if they were written on line). It is not really possible to change the value of a variable and read that new value in the same command (or same line) without using some special "tricks". Delayed expansion is one of them. When you use delayed expansion on a variable, you surround it with ! instead of %. As resultfile will change in each iteration, I use !resultfile! instead of %resultfile%.
If you don't want to save the name of the outputfile in a variable, you can remove the use of the variable and the delayed expansion (remove the EndLocal at the end too).
Good luck!

Batch scripting Return result into a variable

I am creating a generic script that will parse a statement and return the result. I have done so in shell, but don't know how this can happen in batch scripting
Script 1 Main script (main.bat).
SET Myresult=CALL child.bat "Statement"
Now Myresult should store the answer whatever I want to return in this variable.
Solution 1 : SET Myresult in Child.bat and use it in main.bat but now what if the user does not know what the variable name is .
So is their a way to return a value like in java
return xyz
xyz gets captured in the call statement elsewhere.
-------------------------------xxxxxxxxxxxxxxxxxxxxxxx-----------
PART 2
Here are the details of what I am doing .
The so called child script is getSQLResult.bat
What is does is
getSQLResult.bat -q "Select a from abc"
Now this above call statement can be used by anyone any how in any batch script .
So apart from passing a variablename(return name) or writing a for loop to parse the result set is there any simple straight forward way .
Option 1 - Pass the variable name
main.bat
call child.bat myresult "Statement"
echo %myresult%
child.bat
set "%~1=argument was %~2"
Option 2 - Process output of child process
main.bat
for /f "delims=" %%a in ('child.bat "Statement"') do set "myresult=%%a"
echo %myresult%
child.bat
#echo off
echo Argument was %~1
or you can use temporary files, the registry, the clipboard, ... to pass the information, but in any case if you are coding a element (your child.bat) to be reused by you or another person, you are creating an interface between this element and the rest of the code, a expected set of input arguments and a way to return information. Your question
... what if the user does not know what the variable name is?
is answered by the documentation of this interface.
This is the way to do it in batch:
for /f "delims=" %%a in ('echo hello world') do set myresult=%%a
echo it returned: %myresult%
(echo hello world is just an example)
Note: this will return the last (or only) line only. It can be modified to process more lines, but your example implies, there is only one line of output)
EDIT If I understand your edit correct, you want to pass just a statement to an external batchfile, which does the work and gives back the result into a variable, which is defined with the call.
REM child.bat
#echo off
set var=%1
for /f "tokens=1,*" %%i in ("%*") do (
set var=%%i
set statement="%%~j"
)
for /f "delims=" %%a in ('getSQLResult.bat -q %statement%') do set "%var%=%%a"
use it with:
call child.bat result "Select a from abc"
echo %result%
of course it will still return the last (or only) line. Can be easily modified to get the first line. If the output could be more lines, I suggest using an "array" with an counter to avoid the problems, MC ND adresses in his comment to your question. Maybe returning a filename to a file with the multiline output could be another solution.

Resources