This works:
SET server=MyServer
SET db=MyDb
FOR /F "usebackq tokens=1" %%i IN (`sqlcmd -S %server% -d %db% -w200 -h-1 -E -Q "set nocount on; select REPORTING_DATE FROM dbo.CURRENT_REPORTING_DATE"`) DO set REPORTING_DATE=%%i
ECHO The Reporting Date is %REPORTING_DATE%
But when I try to fully qualify the path to sqlcmd...
SET sqlcmdexe="C:\Program Files\Microsoft SQL Server\100\Tools\Binn\sqlcmd.exe" SET server=MyServer SET db=MyDb
FOR /F "usebackq tokens=1" %%i IN (` %sqlcmdexe% -S %server% -d %db%
-w200 -h-1 -E -Q "set nocount on; select REPORTING_DATE FROM dbo.CURRENT_REPORTING_DATE"`) DO set REPORTING_DATE=%%i ECHO The Reporting Date is %REPORTING_DATE%
I get the error:
The system cannot find the path specified.
...presumably because of the spaces in the folder name.
How do I change the path to a tilde path (w/o spaces) or better yet, quote it so that this statement executes properly?
Note that there is a backwards tic before %sqlcmdexe% , not sure why I don't see it, at least in IE6. Yes, 6!
How do I change the path to a tilde path (w/o spaces)
As I don't have sqlcmd.exe installed, I use a different example. See for example this:
#echo off
set sqlcmdexe=C:\Program Files\Internet Explorer\Connection Wizard\icwconn2.exe
echo %sqlcmdexe%
for /f "tokens=*" %%a in ("%sqlcmdexe%") do set sqlcmdexe=%%~sa
echo %sqlcmdexe%
Run on my system, the output is:
C:\temp>envtest
C:\Program Files\Internet Explorer\Connection Wizard\icwconn2.exe
C:\PROGRA~1\INTERN~1\CONNEC~1\icwconn2.exe
But I don't know if this solves your problem.
You have to use the quotes to work with Strings... but You have never use spaces next to equal sign:
set "sqlcmdexe=c:\Program Files\Internet Explorer\Connection Wizard\icwconn2.exe"
echo.%sqlcmdexe%
Hope it helps =)
Related
I'm trying to use a Windows command prompt on Server 2012 R2 to run a batch file with the following command line. I want to run an SQL command (sqlcmd) and return the results to the console window.
This is what I'm currently trying, but sqlcmd keeps throwing back:
Sqlcmd: 'test': Invalid argument. Enter '-?' for help.
FOR /F "tokens=* USEBACKQ" %%F IN (`sqlcmd -S localhost -E -i "backup.sql" -v dbname="test"`) DO (
Echo %%F
)
Note: I have also tried to run just this sqlcmd command (above) in a command prompt with no issues. It's like it does not like the FOR /F loop or something.
However if I try it without parameters/variables it works perfectly!
FOR /F "tokens=* USEBACKQ" %%F IN (`sqlcmd -S localhost -E -i "backup.sql"`) DO (
Echo %%F
)
Does anyone know a way around getting the variables passed to my SQL query using sqlcmd, Windows CMD, as well as a FOR /F loop such as in my first example?
When a line batch code is processed it goes through multiple phases, in a specific order. The order of these phases means that in this case your equals character, = requires special attention. For a full explanation on these phases read this information.
Here's two methods, one of which was already given in the comment area.
I have formatted the command over three lines so that it's clearer, whether you do that too is optional.
Escape the equals character = with a caret ^:
For /F "Delims=" %%A In ('
sqlcmd -S localhost -E -i backup.sql -v dbname^=test
') Do Echo %%A
Or if you wish to doublequote your filename and value:
For /F "Delims=" %%A In ('
sqlcmd -S localhost -E -i "backup.sql" -v dbname^="test"
') Do Echo %%A
Surround the command in doublequotes, ":
For /F "Delims=" %%A In ('
"sqlcmd -S localhost -E -i backup.sql -v dbname=test"
') Do Echo %%A
For /F "Delims=" %%A In ('
"sqlcmd -S localhost -E -i "back up.sql" -v dbname="my test""
') Do Echo %%A
Please note as shown above, whilst it's probably good practice, Microsoft state, 'File paths that contain spaces must be enclosed in quotation marks' and 'Enclose the value in quotation marks if the value contains spaces'. They were not needed in your case and could have been omitted.
I am looking for a solution - a script to automate the process of taking backup of a database in PostgreSQL. As of now I do it manually, that is by right clicking on the db and clicking the backup option.
I did some research and ended up with a script which solves the issue pretty much, ie:
#ECHO OFF
#setlocal enableextensions
#cd /d "%~dp0"
SET PGPATH=C:\PostgreSQL\9.4\bin\
SET SVPATH=d:\
SET PRJDB=Test
SET DBUSR=postgres
FOR /F "TOKENS=1,2,3 DELIMS=/ " %%i IN ('DATE /T') DO SET d=%%i-%%j-%%k
FOR /F "TOKENS=1,2,3 DELIMS=: " %%i IN ('TIME /T') DO SET t=%%i%%j%%k
SET pg_dump=%PRJDB%_%d%_%t%.backup
#ECHO OFF
%PGPATH%pg_dump -h localhost -p 5432 -U postgres %PRJDB% > %SVPATH%%pg_dump%
echo Backup Taken Complete %SVPATH%%pg_dump%
pause
It did take the backup, but the file generated was a sql file, though I did change the extension to .backup. As a result, if I need to restore the DB, and try to restore from the file generated it is not possible. Can someone please provide me with a solution to this problem.
Thanks in advance.
Following script can be used to get the Postgres backup with .backup extension
#echo off
for /f "tokens=1-4 delims=/ " %%i in ("%date%") do (
set dow=%%i
set month=%%j
set day=%%k
set year=%%l
)
set datestr=%day%_%month%_%year%
echo datestr is %datestr%
set BACKUP_FILE=C:\Users\slan\Desktop\backup_test\DBNAME_%datestr%.backup
echo backup file name is %BACKUP_FILE%
SET PGPASSWORD=YOUR_PASSWORD
echo on
bin\pg_dump -i -h localhost -p 5432 -U postgres -F c -b -v -f %BACKUP_FILE% YOUR_DB_NAME
you must have PostgreSQL's bin folder(Ex. C:\PostgreSQL\9.4\bin) along with this script otherwise this will not work as you expect
To schedule the task you can use Windows Task scheduler, here is an example for how to ?? - How to schedule a Batch File to run automatically in Windows 10 / 8 / 7
You can use PGagent for scheduling batch it have multiple advantages over windows scheduler bat scripts
I'm using SQLCMD to get the count of rows in a table, but I also want to be aware if the query hits an error.
The sqlcmd I'm using looks like this:
sqlcmd -S %server% -U %user% -P %pass% -b -Q "select count(*) from %table%"
If it works, it will return:
-----------
10205
(1 rows affected)
(Note, there is a blank line above the ------- for the column name I'm not specifying.)
If I pass in a table that doesn't exist, I get the following response:
Msg 208, Level 16, State 1, Server devServer, Line 1
Invalid object name 'dbo.no_table'.
Since I have the -b flag, I can check ERRORLEVEL for a value (in this case, 1).
To store the count variable, I've been using the following line:
for /F %%i in ('sqlcmd -S %server% -U %user% -P %pass% -b -Q "select count(*) from %table%" ^| findstr /r "[^(][0-9]"') do SET /a rec_count=%%i
After the for, %errorlevel% returns 0. Even inside the do, errorlevel is 0.
Is there any simple way to run sqlcmd, store the count if there is not an error, and print both lines if there is an error?
Commands that are executed by FOR /F are implicitly executed via a new CMD session. For example, with for /f %a in ('echo hello') do ..., the command that is executed becomes C:\Windows\system32\cmd.exe /c echo hello.
Your command is properly setting the ERRORLEVEL, but then the value is lost as soon as the child CMD session terminates and control is returned to your batch script.
So the /b option is not really doing any good for you, and can be dropped.
You can suppress the header info by adding the -h -1 option.
You can suppress the (1 rows affected) message by prefixing your command with set nocount on;
You can add the -r 1 option to cause error messages to appear on stderr instead of stdout. This will prevent FOR /F from processing any error, and the error message will appear on the screen instead.
You can clear the rec_count variable before you execute the command. Then it will remain undefined if there was an error, else it will contain the count if there was no error.
set "rec_count="
for /f %%A in (
'sqlcmd -S %server% -U %user% -P %pass% -h -1 -r 1 -Q "set nocount on;select count(*) from %table%"'
) do set "rec_count=%%A"
if not defined rec_count echo There was an error!
One other thing you might consider is using environment variables recognized by SQLCMD for your server, username, and password. Then you won't have to use the -S, -U, or -P options. This is especially handy if your batch script runs many SQLCMD commands.
set "sqlcmdServer=YourServer"
set "sqlcmdUser=YourUserName"
set "sqlcmdPassword=YourPassword"
set "rec_count="
for /f %%A in (
'sqlcmd -h -1 -r 1 -Q "set nocount on;select count(*) from %table%"'
) do set "rec_count=%%A"
if not defined rec_count echo There was an error!
The reason errorlevel does not seem to be getting set is because the for command is executing successfully, regardless of how the code that it loops through executes. So you can only interact with the errorlevel that is set by the sqlcmd command on the same line (inside the for loop brackets).
You should be able to use || (double pipe) after the sqlcmd command. Any code after || will only run if the previous command fails. Example:
notACommand || echo test
Will return "test". While the following will output only "a command":
echo a command || echo test
I can't test it, but something like the following should work for you:
for /F "EOL=(" %%i in ('sqlcmd -S %server% -U %user% -P %pass% -b -Q "select count(*) from %table%" ^|^| echo fail') do (
SET rec_count=%%i
)
if "%rec_count%"=="fail" echo SQL command failed
If the output is exactly as you say, then you should not need the findstr command - just set ( open bracket as an EOL character in the for loop, so you effectively drop the "(1 rows affected)" line. You will probably want to use the variables differently, but this is just one way you can tell if the sqlcmd command has failed or not.
As for outputting the error - a bad solution is to run the same sqlcmd command again. Something like the following:
set command=sqlcmd -S %server% -U %user% -P %pass% -b -Q "select count(*) from %table%"
for /F "EOL=(" %%i in ('%command% ^|^| echo fail') do SET rec_count=%%i
if "%rec_count%"=="fail" (%command%) else echo rec_count is %rec_count%
Note that I removed the /a switch when setting the rec_count variable, because it can now be set as a word.
Okay, a brief explanation of what I am doing: I use Windows Media Center (Windows 7) to record Jeopardy every evening. I then use Handbrake to convert the .wtv files to .mkv files and then transfer them to my NAS so I can watch them later using Plex Media Server/Center. Rather than doing this "by hand", I'm trying to automate the process using a batch file as a scheduled task. Initially, I had set up a script so that I could right-click > Send To > convert.bat and it would initiate the command-line interface for Handbrake and convert the file, move the output to my NAS, and delete the original file (worked great).
Now, what I'm doing is initiating the batch script as a scheduled task and looping through the contents of my "recorded tv" directory and looping through any .wtv files to convert/move/delete them.
The problem lies in the fact that Windows Media Center correctly names the Jeopardy files with the "!" in them (Eg: Jeopardy!_KHQ_2012_12_04_21_12_12.wtv), which completely bricks my script. The "Send To" batch file worked great, but when I loop through the *.wtv files in the directory, it returns all the filenames with the "!" stripped out which means I can't do squat with them. Files without "!" do process without a hitch.
Thanks in advance to anyone who can get me pointed in the right direction! (and if you happen to see any other areas where this script could be improved, that's fine too...)
Here is the basic code that I am attempting to use:
#echo off
setlocal ENABLEDELAYEDEXPANSION
SET count=0
SET getFolder=C:\Users\Public\Recorded TV\
SET ripFolder=C:\Rips\
SET putFolder=Z:\Videos\Recorded TV\
FOR %%F IN ("%getFolder%*.wtv") DO (
SET /A count=!count!+1
REM DETERMINE OUTPUT FILENAME
for /f "tokens=5,6,7,8,9,10 delims=\_" %%a in ("%%F") do (
set show=%%a
set station=%%b
set year=%%c
set month=%%d
set day=%%e
set hour=%%f
REM GENERATE OUTPUT NAMING CONVENTION
set output=!show! s!year!e!month!!day! !hour!
)
REM PROCESS WITH HANDBRAKE CLI
"C:\Program Files\Handbrake\HandBrakeCLI.exe" -i "%%F" -t 1 -c 1 -o %ripFolder%!OUTPUT!.mkv -f mkv --deinterlace="fast" --crop 58:60:2:2 --strict-anamorphic -e x264 -q 20 --vfr -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0 --gain=0 --audio-copy-mask none --audio-fallback ffac3 -x ref=1:weightp=1:subq=2:rc-lookahead=10:trellis=0:8x8dct=0 --verbose=1
REM MOVE CONVERTED FILE TO NAS
copy "%ripFolder%!OUTPUT!.mkv" "%putFolder%"
REM DELETE ORIGINAL
del "%%F"
REM DELETE LOCAL RIP
del "%ripFolder%!output!.mkv"
)
echo %count% files processed
pause
ENDLOCAL
As you have recognized, the exclamation mark is stripped before you can escape it.
That's because you expand the FOR-loop variable %%F while delayed expansion is enabled, and the exclamation mark tries to expand a variable.
You need to toggle the delayed expansion here, as the variable contents are safe when using with delayed expansion, but to get the value you need the disabled mode.
#echo off
setlocal DisableDelayedExpansion
SET count=0
FOR %%F IN ("%getFolder%*.wtv") DO (
set "orgFile=%%F"
SET /A count+=1
REM DETERMINE OUTPUT FILENAME
for /f "tokens=5,6,7,8,9,10 delims=\_" %%a in ("%%F") do (
set show=%%a
set station=%%b
set year=%%c
set month=%%d
set day=%%e
set hour=%%f
setlocal EnableDelayedExpansion
REM GENERATE OUTPUT NAMING CONVENTION
set output=!show! s!year!e!month!!day! !hour!
)
REM PROCESS WITH HANDBRAKE CLI
"C:\Program Files\Handbrake\HandBrakeCLI.exe" -i "%%F" -t 1 -c 1 -o %ripFolder%!OUTPUT!.mkv -f mkv --deinterlace="fast" --crop 58:60:2:2 --strict-anamorphic -e x264 -q 20 --vfr -a 1 -E faac -B 160 -6 dpl2 -R Auto -D 0 --gain=0 --audio-copy-mask none --audio-fallback ffac3 -x ref=1:weightp=1:subq=2:rc-lookahead=10:trellis=0:8x8dct=0 --verbose=1
REM MOVE CONVERTED FILE TO NAS
copy "%ripFolder%!OUTPUT!.mkv" "%putFolder%"
REM DELETE ORIGINAL
del "!orgFile!"
REM DELETE LOCAL RIP
del "%ripFolder%!output!.mkv"
endlocal
)
How do I do this properly. I'm trying to name the sql file that is being produced by mysqldump into the current date and time. I've already some research in this site and found a code in here: How to get current datetime on Windows command line, in a suitable format for using in a filename?
Tried to mixed it up with my current code and I came up with this one. The file is named into the current date and time but its only a 1kb file and does not produce a .sql file.
It is supposed to be a 7 kb sql file.
#For /f "tokens=2-4 delims=/ " %%a in ('date /t') do #(set mydate=%%c-%%a-%%b)
#For /f "tokens=1-2 delims=/:" %%a in ('time /t') do #(set mytime=%%a%%b)
#echo mydate= %mydate%
#echo mytime= %mytime%
mysqldump -u root -p --add-drop-table --create-options --password= onstor >c:\%mydate%_%mytime%.sql
UPDATE
I don't think there's a problem with the mysqldump command since it works well when I do it this way. The code below just uses the date as its filename.
#For /F "tokens=2,3,4 delims=/ " %%A in ('Date /t') do #(
Set Month=%%A
Set Day=%%B
Set Year=%%C
)
#echo DAY = %Day%
#echo Month = %Month%
#echo Year = %Year%
mysqldump -u root --add-drop-table --create-options --password= onstor >c:\%Day%-%Month%-%Year%.sql
Please help, thanks.
On Linux, simply put $(date +%Y-%m-%d-%H.%M.%S) to show date and time in the file name, so it looks like:
mysqldump -u <user> -p <database> | bzip2 -c > <backup>$(date +%Y-%m-%d-%H.%M.%S).sql.bz2
(This command also compresses the file using bzip2)
I think the syntax of your mysqldump command is wrong;
mysqldump -u root -p --add-drop-table --create-options --password= onstor
You use both -p and --pasword=, you should only use one option. And there is a space before the password.
Just try to run the mysqldump command on the commandline to see error messages. Alternatively add 2>&1 at the end of the command in the batchfile. Then you would also see error messages in the output file.
mysqldump -u root --add-drop-table --create-options --password=onstor >c:\%mydate%_%mytime%.sql 2>&1
For those who want to get this to work in crontab, in that case it's a bit different:
30 01 * * * /opt/bitnami/mysql/bin/mysqldump -u root --password=MySecretPass database_name | gzip > /path/backup/`date "+\%d-\%m-\%y_\%H:\%M"`.gz