SQLCMD load sql script - sqlcmd

How do I make SQLCMD retrieve any SQL file name using –i? (> .sql)
If there will always be only 1 file *.sql in the directory?

Does this mean that you want to run any and all .sql files in the directory? If so:
=== PowerShell
Get-ChildItem -File -Path 'D:\path\to\sqlfiles' -Filter '*.sql' |
ForEach-Object {
& sqlcmd.exe -S 'DBNAME' -i $_.FullName
}
=== CMD
FOR /F "delims=" %%A IN ('DIR /B "D:\path\to\sqlfiles\*.sql"') DO (
sqlcmd.exe -S DBNAME -i "%%~A"
)

Related

Windows Batch - Extract values for ffmpeg processing

I have dozens of json files, and I am trying to find two values in each of them and assign the results to two separate variables for ffmpeg processing.
An example json file looks like this:
{
"year": "2018",
"track": "12",
... other data omitted
}
I wish to extract 2018 and 12 so that I can use them in the following ffmpeg command:
ffmpeg -i "same_file_name_as_json.m4a" -metadata:s:a:0 year=2018 --metadata:s:a:0 track=12 -acodec libmp3lame "same_file_name_as_json.mp3"
Is it possible to write a single batch file to achieve the desired result? Any help would be greatly appreciated as I am a complete novice at findstr and setting variables. Thank you.
EDITED:
set "year=" & set "track="
for %%i in (*.json) do (
for /f "usebackq tokens=1,2 delims={:}, " %%a in ("%%i") do (
set "%%~a=%%~b"
if defined year if defined track goto :CONT
)
:CONT
C:\ffmpeg -i "%%~ni.m4a" -metadata:s:a:0 year=%year% -metadata:s:a:0 track=%track% -acodec libmp3lame "%%~ni.mp3"
)
pause
Windows batch scripting does not understand the JSON file format, so it is better to use a language natively supports it. It is not the best idea to treat JSON as "normal" text, because only a slight change (for instance, added, deleted, or moved line-breaks) that do not violate the JSON format can still make big troubles then.
That said, given that the JSON file exactly appears as you have shown it and it features Unix- or DOS/Windows-style line-breaks (that is, a carriage-return character followed by a line-feed character), this code could work for you:
for /F "usebackq tokens=1,2 delims={:}, " %%M in ("file.json") do set "%%~M=%%~N"
echo year = %year%
echo track = %track%
If you have got a huge JSON file you do not want to unnecessarily fully process, you could use this code instead:
set "year=" & set "track="
for /F "usebackq tokens=1,2 delims={:}, " %%M in ("file.json") do (
set "%%~M=%%~N"
if defined year if defined track goto :CONT
)
:CONT
echo year = %year%
echo track = %track%
If the (non-array) values you want to extract may also contain one of the defined delimiters ({, :, }, ,, SPACE), you could extend the code to this, given that the values do not contain the characters *, ?, <, >:
set "year=" & set "track="
for /F "usebackq tokens=1,* delims={:}, " %%M in ("file.json") do (
for %%K in (%%N) do set "%%~M=%%~K"
if defined year if defined track goto :CONT
)
:CONT
echo year = %year%
echo track = %track%
To prevent the script from assigning unwanted superfluous variables, you may try this:
for /F "usebackq tokens=1,2 delims={:}, " %%M in ("file.json") do (
if "%%~M"=="year" (set "%%~M=%%~N") else if "%%~M"=="track" set "%%~M=%%~N"
)
echo year = %year%
echo track = %track%
Or this, which prepreocesses the data by the findstr command and filters out the desired lines:
for /F "tokens=1,2 delims={:}, " %%M in ('
findstr /R /C:"^ *\"year\" *:" /C:"^ *\"track\" *:" "file.json"
') do set "%%~M=%%~N"
echo year = %year%
echo track = %track%
Based on your edit, let me suggest to use the last of the above methods, because there is no goto :CONT, which cannot be used within loops as it breaks the block context, and it does not assign additional unwanted variables. Since variables are written and read within the loop body, you have to enable and apply delayed variable expansion. I would do all that the following way:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem /* Iterate over the `*.json` files in the current working directory (`%CD%`);
rem to use the parent directory of this script, use `%~dp0*.json` instead: */
for %%I in ("*.json") do (
rem // Store name of current JSON file in variable:
set "name=%%~nI"
rem // Clear variables for later check for availability:
set "year=" & set "track="
rem // Process the current JSON file:
for /F "tokens=1,2 delims={:}, " %%M in ('
findstr /R /C:"^ *\"year\" *:" /C:"^ *\"track\" *:" "%%~I"
') do (
rem // Assign year and track variables:
set "%%~M=%%~N"
rem // Check of both year and track are available:
if defined year if defined track (
rem // Toggle delayed expansion to avoid troubles with `!`:
setlocal EnableDelayedExpansion
rem // Eventually execute `ffmpeg` tool using all the derived data:
ffmpeg -i "!name!.m4a" -metadata:s:a:0 year=!year! -metadata:s:a:0 track=!track! -acodec libmp3lame "!name!.mp3"
endlocal
)
)
)
endlocal
exit /B
I have dozens of json files...
Windows' cmd doesn't support JSON, so you'd have to resort to PowerShell, or use an external tool that does. You might find xidel interesting.
To extract the value for "year" and "track":
xidel -s input.json -e "$json/(year,track)"
#or
xidel -s input.json -e "$json/year,$json/track"
2018
12
To export to a variable %year% and %track%:
FOR /F "delims=" %A IN ('xidel -s input.json -e "$json/(year:=year,track:=track)" --output-format^=cmd') DO %A
#or
FOR /F "delims=" %A IN ('xidel -s input.json -e "year:=$json/year,track:=$json/track" --output-format^=cmd') DO %A
You don't however need variables to create the strings (ffmpeg commands) you want. xidel can do that too.
You could use a FOR-loop to iterate over all your JSON-files...
FOR %A IN (*.json) DO #xidel -s %A -e "$json/concat('ffmpeg -i \"%~nA.m4a\" -metadata:s:a:0 year=',year,' --metadata:s:a:0 track=',track,' -acodec libmp3lame \"%~nA.mp3\"')"
ffmpeg -i "name-of-json-file.m4a" -metadata:s:a:0 year=2018 --metadata:s:a:0 track=12 -acodec libmp3lame "name-of-json-file.mp3"
...but to call xidel for each and every JSON-file is very inefficient. xidel can do this much more efficiently.
xidel's equivalent for FOR %A IN (*.json) DO #ECHO %A is xidel -se "file:list(.,false(),'*.json')"
Then you can use the following query to process all your JSON-files at once:
xidel -se "for $x in file:list(.,false(),'*.json') return json-doc($x)/concat('ffmpeg -i \"',replace($x,'json','m4a'),'\" -metadata:s:a:0 year=',year,' --metadata:s:a:0 track=',track,' -acodec libmp3lame \"',replace($x,'json','mp3'),'\"')"
Prettified command/query:
xidel -se ^"^
for $x in file:list(.,false(),'*.json') return^
json-doc($x)/concat(^
'ffmpeg -i \^"',^
replace($x,'json','m4a'),^
'\^" -metadata:s:a:0 year=',^
year,^
' --metadata:s:a:0 track=',^
track,^
' -acodec libmp3lame \^"',^
replace($x,'json','mp3'),^
'\^"'^
)^
"

How to read JSON data in batch script

I have a JSON file, named "Config.json", that looks like this:
{ "RunEnvironment": "DEV"}
In a batch file under the same directory, I want to read the value of the "RunEnvironment" element.
My batch script would look like:
if [jsonElement] == 'DEV' (
:: do something
)
Can anyone show me how to do this?
In PowerShell for example, you could do:
> If((Get-Content '.\Config.json'|ConvertFrom-Json).RunEnvironment -eq 'DEV'){"is DEV:Whatever"}
is DEV:Whatever
To be on topic on cmd line
> for /f "tokens=1,2 delims=:{} " %A in (Config.json) do #If "%~B"=="Dev" #Echo (%~A = %~B)
(RunEnvironment=DEV)
In a batch file
#Echo off
for /f "tokens=1,2 delims=:{} " %%A in (Config.json) do (
If "%%~B"=="Dev" Echo (%%~A=%%~B^)
)
The Echo (%%~A=%%~B^) could be replaced with whatever you plan to do.
If all you need to do is perform a specific command only if the value of RunEnvironment is DEV then this should be all you require, (from a batch-file or the command-line):
"%__APPDIR__%FindStr.exe" /IRC:"\"RunEnvironment\":\ \ *\"DEV\"" "Config.json">NUL 2>&1&&Echo Your command here
You'd simply replace Echo Your command here with your intended command.
Yo can do in this way
#echo off
set string={ "RunEnvironment": "DEV" }
for /f "tokens=3,5" %%a in ('echo %string%') do set d=%%~a
if "%d%" == "DEV" echo %d%
pause & goto :EOF
In a batch file:
#ECHO off
SET "FilenameForJsonFile=Config.json"
SET "FilenameForRunEnvironment=RunEnvironment.txt"
powershell -Command "Select-String -Pattern 'RunEnvironment\"\: \".*?\"' .\%FilenameForJsonFile% ^| ForEach-Object { $_.Matches.Value.substring(18,$_.Matches.Value.Length-19) }>%FilenameForRunEnvironment%
FOR /f "delims=" %%x IN (%FilenameForRunEnvironment%) DO SET JsonElement=%%x
IF %JsonElement%==DEV (ECHO development environment) ELSE (ECHO abc123 environment)

How to get JSON from cURL as array in a batch file

Hi I'm very new in batch files. I try to do something simular to my bash script. So here is my problem:
I want to get all versions/tags from a github repository to generate a configuration file for the php documentor sami. But how can I write the JSON into a variable in batch to get the versions? In my bash script I did this and it's working fine:
function jsonDecode() {
json=$1
key=$2
echo ${json} | jq -r ${key}
}
ghUser="MisterMarlu"
ghRepo="sentence"
json=$(curl "https://api.github.com/repos/${ghUser}/${ghRepo}/tags")
versions=$(echo "${json}" | jq -c ".[]")
for version in ${versions[#]}; do
versionNumber=$(jsonDecode ${version} ".name")
echo " ->add( '${versionNumber}', '${versionNumber}' )" >> ${config}
done
# Here comes alot of code below this for loop..
This will output "v0.0.1" and "v0.0.2". Bus how can I do this in a batch file?
EDIT
Here is the JSON response where I need just the "name" as array:
[
{
"name": "v0.0.2",
"zipball_url": "https://api.github.com/repos/MisterMarlu/sentence/zipball/v0.0.2",
"tarball_url": "https://api.github.com/repos/MisterMarlu/sentence/tarball/v0.0.2",
"commit": {
"sha": "82c4b6d74cc16816104934114766f0328e77ee66",
"url": "https://api.github.com/repos/MisterMarlu/sentence/commits/82c4b6d74cc16816104934114766f0328e77ee66"
},
"node_id": "MDM6UmVmMTMzMDM1MDMxOnYwLjAuMg=="
},
{
"name": "v0.0.1",
"zipball_url": "https://api.github.com/repos/MisterMarlu/sentence/zipball/v0.0.1",
"tarball_url": "https://api.github.com/repos/MisterMarlu/sentence/tarball/v0.0.1",
"commit": {
"sha": "0cf1a83a51716da3f42915c9eab571166845bb0b",
"url": "https://api.github.com/repos/MisterMarlu/sentence/commits/0cf1a83a51716da3f42915c9eab571166845bb0b"
},
"node_id": "MDM6UmVmMTMzMDM1MDMxOnYwLjAuMQ=="
}
]
To process the output of another program you need a for /f
parsing the lines filtered by findstr
:: Q:\Test\2018\06\12\SU_50811698.cmd
#Echo off & SetLocal EnableDelayedExpansion
Set "ghUser=MisterMarlu"
Set "ghRepo=sentence"
Set "Version="
For /f "tokens=1,2 delims=:, " %%U in ('
curl "https://api.github.com/repos/%ghUser%/%ghRepo%/tags" 2^>Nul ^| findstr /i "\"name\""
') do Set "Version=!Version!,%%~V"
If defined Version (set "Version=%Version:~1%") Else (Set "Version=n/a")
Set Version
Sample output:
> Q:\Test\2018\06\12\SU_50811698.cmd
Version=v0.0.2,v0.0.1
You are aware that batch has no real arrays?
Just an alternative in PowerShell:
$ghUser="MisterMarlu"
$ghRepo="sentence"
$URL = "https://api.github.com/repos/$ghUser/$ghRepo/tags"
$Json=(curl.exe $URL)|ConvertFrom-json
$Json | Select name
name
----
v0.0.2
v0.0.1
With Xidel it's simple as:
xidel -s "https://api.github.com/repos/MisterMarlu/sentence/tags" -e "join($json()/name,',')"
This puts out: v0.0.2,v0.0.1.
To export this as $config/%config%...
Bash:
eval "$(xidel -s "https://api.github.com/repos/MisterMarlu/sentence/tags" -e '
config:=join(
$json()/name,
","
)' --output-format=bash
)"
Batch:
FOR /F "delims=" %%A IN ('xidel.exe -s "https://api.github.com/repos/MisterMarlu/sentence/tags" -e ^"
config:^=join^(
$json^(^)/name^,
'^,'
^)^" --output-format^=cmd
') DO %%A
or...
FOR /F "delims=" %%A IN ('xidel.exe -s "https://api.github.com/repos/MisterMarlu/sentence/tags" -e "config:=join($json()/name,',')" --output-format=cmd') DO %%A

parse csv to make more readable

I am using PsInfo from sysinternals to return drive information in the form of a csv.
When I run this command.
psinfo -c -d volume
I get the following output.
PCName,,C:,Fixed,NTFS,,930.97 GB,705.81 GB,75.8%,D:,CD-ROM,,,,,0.0%,G:,Fixed,NTFS,My Book,1862.98 GB,889.71 GB,47.8%
My goal here is to parse that output to achieve this format:
PCNAME,,
,,C:,Fixed,NTFS,,930.97 GB,705.81 GB,75.8%
,,G:,Fixed,NTFS,My Book,1862.98 GB,889.71 GB,47.8%
So when the output is read by a spreadsheet viewer it appears readable and organized.
I've tried using regex to match the drive letter bit I don't know how to correctly capture the output.
Edit: (forgot to actually post my code...)
This is what I have so far.
ECHO OFF
For /f "tokens=1*" %%x in ('net view ^| find "\\"') do (psinfo %%x filter -d -c >> out.csv & echo. >> out.csv)
::used to remove blanmk lines from output
#jrepl "^[ \t]*(.*?)[ \t]*$" "$1?$1:false" /jmatch /f out.csv /o -
pause
#ECHO OFF
SETLOCAL enabledelayedexpansion
FOR /f "delims=" %%a IN ('psinfo -c -d volume') DO SET "var=%%a"
SET "var2=!var:%%=\!"
SET "retained="
:again
REM FOR /f "tokens=delims==:" %%a IN () DO
FOR /f "tokens=1*delims=:" %%a IN ("%var2%") DO (
CALL :FORMAT "%%a"
SET "var2=%%b"
IF NOT "%%b"=="" GOTO again
)
GOTO :EOF
:FORMAT
SET "data=%~1"
IF "%data:~-1%"=="\" (SET "data=%retained%:%data%") ELSE (SET "data=%retained%:%data:~,-2%")
IF DEFINED retained (
ECHO ,,!data:\=%%!
) ELSE (
ECHO %data:~1%,
)
SET "retained=%~1"
SET retained=%retained:~-1%
GOTO :eof
substitutes \ for % for ease of processing.
This worked for me. Given this example you should be able to play around with the format of the output you desire.
#echo off
FOR /F "tokens=1* delims=," %%G IN ('psinfo -c -d volume') DO (
SET "pcname=%%G"
SET "driveinfo=%%H"
)
set driveinfo="%driveinfo:,=","%"
:LOOP
FOR /F "tokens=1-7* delims=," %%G IN ("%driveinfo%") DO (
echo "%pcname%",%%G,%%H,%%I,%%J,%%K,%%L,%%M
SET "driveinfo=%%N"
)
IF DEFINED driveinfo GOTO LOOP
Output
"COCO","C:","Fixed","NTFS","","930.97 GB","705.81 GB","75.8%"
"COCO","G:","Fixed","NTFS","My Book","1862.98 GB","889.71 GB","47.8%"
And here is the code changed to replicate your exact needed Output.
#echo off
FOR /F "tokens=1* delims=," %%G IN ('psinfo -c -d volume') DO (
SET "pcname=%%G"
SET "driveinfo=%%H"
)
set driveinfo="%driveinfo:,=","%"
echo %pcname%,,
:LOOP
FOR /F "tokens=1-7* delims=," %%G IN ("%driveinfo%") DO (
echo ,,%%~G,%%~H,%%~I,%%~J,%%~K,%%~L,%%~M
SET "driveinfo=%%N"
)
IF DEFINED driveinfo GOTO LOOP
And here is doing it in a couple of less lines.
#echo off
setlocal enabledelayedexpansion
FOR /F "tokens=1* delims=," %%G IN ('psinfo -c -d volume') DO (
echo %%G,,
SET "driveinfo=%%H"
)
set "drive2=echo ,,!driveinfo:%%=%%&echo,,!"
%drive2:~0,-1%
You can get the same information with Powershell, eg with the Get-Volume command. This returns, everything except the ration eg:
DriveLetter FileSystemLabel FileSystem DriveType HealthStatus OperationalStatus SizeRemaining Size
----------- --------------- ---------- --------- ------------ ----------------- ------------- ----
D CD-ROM Healthy Unknown 0 B 0 B
C Win7 NTFS Fixed Healthy OK 43.59 GB 238.03 GB
H Projects NTFS Fixed Healthy OK 96.73 GB 375.24 GB
Get-Volume returns volume information objects. The shell just displays the most common ones.
You can select only the properties you want, and add more columns with the select command:
Get-Volume | where {$_.DriveType -ne 'CD-ROM'}
| select DriveLetter, FileSystemLabel,FileSystem,SizeRemaining, Size,
#{Name="Ratio";Expression={"{0:P}" -f ($_.SizeRemaining/$_.Size)}}
|Format-Table
DriveLetter FileSystemLabel FileSystem SizeRemaining Size Ratio
----------- --------------- ---------- ------------- ---- -----
C Win7 NTFS 46793633792 255584587776 18,31%
H Projects NTFS 103853056000 402911129600 25,78%
I'm cheating a bit here, by filtering out the CD ROM with where
If the results are too long to fit in the window, Powershell displays them as a list of name/values. The final Format-Table is used to force Powershell to format the results as a table
I can store the table to a file with a normal redirection :
Get-Volume | where {$_.DriveType -ne 'CD-ROM'}
| select DriveLetter, FileSystemLabel,FileSystem,SizeRemaining, Size,
#{Name="Rate";Expression={"{0:P}" -f ($_.SizeRemaining/$_.Size)}}
|Format-Table > somefile.txt
or I can export the results to a real CSV with Export-CSV
Get-Volume | where {$_.DriveType -ne 'CD-ROM'}
| select DriveLetter, FileSystemLabel,FileSystem,SizeRemaining, Size,
#{Name="Rate";Expression={"{0:P}" -f ($_.SizeRemaining/$_.Size)}}
| Export-CSV somefile.csv
The following code snippet reformats the output of psinfo -c -d volume as you wish. Since it seems that you want it filtered by drive type (Fixed) according to your sample data, I implemented such a feature; to not filter anything, simply change line set "FILTER=Fixed" to set "FILTER=":
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "FILTER=Fixed"
(set LF=^
%= empty line =%
)
for /F "tokens=1,* delims=, eol=," %%K in ('psinfo -c -d volume') do (
echo(%%K,,
set "LINE=%%L"
setlocal EnableDelayedExpansion
set ^"LINE=!LINE:%%,=%%^%LF%%LF%!^"
for /F "delims= eol=," %%E in ("!LINE!") do (
endlocal
if defined FILTER (
for /F "tokens=2 delims=, eol=," %%F in ("%%E") do (
if "%%F"=="%FILTER%" (
echo(,,%%E
)
)
) else (
echo(,,%%E
)
setlocal EnableDelayedExpansion
)
endlocal
)
endlocal
exit /B

Script for MySQL backup to multiple files

I am creating a script to back up the MySQL running on a Windows 2012 server, using PowerShell. Unlike other tips found here, I want to generate a .sql file for each of the databases.
This post shows how to create multiple files. I adapted it to PowerShell:
Get-ChildItem -Path "$($MYSQL_HOME)\data" | cmd /C "$($MYSQL_HOME)\bin\ mysql -u -s -r $($dbuser) -p$($dbpass) -e 'databases show' '| while read dbname; cmd /C "$($MYSQL_HOME)\bin\mysqldump.exe --user = $($dbuser) --password = $($dbpass) --databases $dbname> $($BKP_FOLDER)\$dbname($BACKUPDATE).sql "
but it returns error in while.
What should I change so that you can generate multiple .sql, one for each database?
Your entire commandline is b0rken. Throw it away and start over. Try something like this:
Set-Location "$MYSQL_HOME\bin"
& .\mysql.exe -N -s -r -u $dbuser -p$dbpass -e 'show databases' | % {
& .\mysqldump.exe -u $dbuser -p$dbpass --single-transaction $_ |
Out-File "$BKP_FOLDER\${_}$BACKUPDATE.sql" -Encoding Ascii
}
Example using an input from file result of mysqldump.
#Variables#####
# Debe especificar la ruta completa, por ejemplo C:\Temp\archivo.txt
$file = $args[0]
$c = ""
$i = 0
$startSafe = 0;
###############
New-Item -ItemType Directory -Force -Path .\data
$x = 0;
foreach ($f in [System.IO.File]::ReadLines($file)) {
if ($f -like '-- Dumping data for table *') {
$startSafe = 1;
$x = $f.split('`')[1];
write $x;
}
if ($startSafe) {
if($f -eq "UNLOCK TABLES;"){$i += 1; $f >> .\data\$x.out.sql; $startSafe = 0; $x = $i}
if($f -ne "UNLOCK TABLES;"){ $f >> .\data\$x.out.sql;}
}
}