运行 批处理文件中的 sqlcmd 有效,但 运行 与计划任务相同的批处理文件有效但什么都不做
Running sqlcmd in batch file works but running the same batch file as a scheduled task works and does nothing
我看过很多 SO questions/answers,虽然有些看起来与我的问题相似,但它们似乎并不相似。给出的答案解决了问题询问的问题,但不会解决我的问题。
我有一个批处理文件...
@ECHO ON
ECHO Disabling the following... >> C:\App\Debug.log
ECHO - V1 >> C:\Apps\Debug.log
FOR /F "tokens=* USEBACKQ" %%F IN (`sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1'"`) DO (
Echo %%F >> C:\Apps\Debug.log
)
EXIT /B
当我在命令提示符下 运行 这个文件时,它工作得很好。当我 运行 它作为计划任务时,它向我显示了回声,但没有显示预期的 for 循环。
- 是的,我已确保计划任务的用户名(使用 whoami)与我执行的手动 运行 设置相同。
- 是的,我知道用户 运行 对脚本拥有所有权限(文件访问和数据库访问),因为它在命令提示符下运行良好运行。
- 计划任务设置为运行用户是否登录。
有什么想法可能是错误的,或者我可以为调试目的尝试什么?
谢谢!
sqlcmd
可能还不够。 cmd.exe
在计划任务环境中使用 local PATHEXT
和 local PATH
可能无法找到可执行文件环境变量。应使用完整的限定文件名指定可执行文件,即驱动器 + 路径 + 名称 + 扩展名。然后批处理文件不再依赖于环境变量 PATH
和 PATHEXT
因为所有文件都使用完整的限定文件名引用。
for
执行指定的命令行,并在后台启动一个带有 %ComSpec% /c
并附加指定命令行的命令进程。这意味着执行后 Windows 安装在驱动器 C:
上:
C:\Windows\System32\cmd.exe /c sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1'"
for
捕获为处理已启动命令进程的 STDOUT 而编写的所有内容。捕获的输出行在开始 cmd.exe
终止后由 for
逐行处理。启动的 cmd.exe
或 Windows 命令处理器在后台执行的 commands/executables 处理 STDERR 的错误消息被重定向到处理 命令进程的 STDERR 处理批处理文件并打印到控制台。但是没有控制台window就运行一个批处理文件作为计划任务。因此在这种情况下无法看到错误消息。
可以在此处轻松修改 for
命令行,以便将错误消息也写入 C:\Apps\Debug.log
。
FOR /F "tokens=* USEBACKQ" %%F IN (`sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1' 2^>^&1"`) DO (
Microsoft 文章 Using command redirection operators 解释了 2>&1
。 >
和 &
这两个运算符必须使用 ^
进行转义,以便在 Windows 命令处理器解析 for
命令行之前解释为文字字符,然后最终执行 for
使用指定的命令行执行下一个 %ComSpec% /c
,其中 2^>^&1
已经更改为 2>&1
.
日志文件 C:\App\Debug.log
是否包含此修改后的两行?
'sqlcmd' is not recognized as an internal or external command,
operable program or batch file.
是的,然后启动 cmd.exe
没有找到文件名为 sqlcmd
的可执行文件。最好的解决方案是使用完整的限定文件名引用此可执行文件。另见:
否则 sqlcmd
可能会输出一条错误消息,现在应该也在日志文件中 C:\App\Debug.log
。
也可以使用以下命令行让后台cmd.exe
将错误信息写入单独的错误日志文件C:\App\Error.log
:
FOR /F "tokens=* USEBACKQ" %%F IN (`sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1'" 2^>C:\App\Error.log`) DO (
"tokens=* usebackq"
导致首先删除非空行上的所有前导水平制表符和正常 spaces for
,然后检查剩余行是否以 [=47= 开头] 在这种情况下,该行也将被忽略,并最终将捕获的不以 ;
开头且前导 tabs/spaces 删除的行分配给循环变量 F
以进行进一步处理。
更好的做法是使用不包含在双引号中的选项 usebackq^ delims^=^ eol^=
,这需要转义两个 space 和两个带脱字符 ^
的等号,以将其解释为文字在执行 for
之前解析命令行时 cmd.exe
的字符。由于定义了一个空的分隔符列表,所以使用 delims=
完成了行拆分行为。由于行尾字符从默认 ;
修改为无字符,因此不再忽略除空行之外的任何行。
最后,echo
行上的 space 留给重定向运算符 >>
也由 echo
输出,因此写为尾随 space到日志文件中。因此,在打印将 echo
重定向到文件的行时,不应将 space 留给 >
或 >>
。但是必须注意省略留给重定向运算符的 space 字符。留给重定向运算符的 word 不应该是 1
, 2
, ..., 9
因为这会导致输出重定向到这些编号句柄而不是字符 1
、2
等。因此,如果要将未知文本写入文件,最好先指定重定向运算符 >
或>>
和完整的限定文件名,然后是 echo
命令和要输出的文本。另见:
带有 echo
的三个命令行将用于此批处理文件:
ECHO Disabling the following...>> C:\App\Debug.log
ECHO - V1>> C:\Apps\Debug.log
>>C:\Apps\Debug.log ECHO %%F
following...
和 V1
一样可以安全地正确写入文件。 %%F
可能只是 1
或以 space 和一个数字结尾的字符串,因此最好在最后一个 echo
命令行中首先指定重定向以获取最后由 cmd.exe
命令行 ECHO %%F 1>>C:\Apps\Debug.log
.
执行
我看过很多 SO questions/answers,虽然有些看起来与我的问题相似,但它们似乎并不相似。给出的答案解决了问题询问的问题,但不会解决我的问题。
我有一个批处理文件...
@ECHO ON
ECHO Disabling the following... >> C:\App\Debug.log
ECHO - V1 >> C:\Apps\Debug.log
FOR /F "tokens=* USEBACKQ" %%F IN (`sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1'"`) DO (
Echo %%F >> C:\Apps\Debug.log
)
EXIT /B
当我在命令提示符下 运行 这个文件时,它工作得很好。当我 运行 它作为计划任务时,它向我显示了回声,但没有显示预期的 for 循环。
- 是的,我已确保计划任务的用户名(使用 whoami)与我执行的手动 运行 设置相同。
- 是的,我知道用户 运行 对脚本拥有所有权限(文件访问和数据库访问),因为它在命令提示符下运行良好运行。
- 计划任务设置为运行用户是否登录。
有什么想法可能是错误的,或者我可以为调试目的尝试什么? 谢谢!
sqlcmd
可能还不够。 cmd.exe
在计划任务环境中使用 local PATHEXT
和 local PATH
可能无法找到可执行文件环境变量。应使用完整的限定文件名指定可执行文件,即驱动器 + 路径 + 名称 + 扩展名。然后批处理文件不再依赖于环境变量 PATH
和 PATHEXT
因为所有文件都使用完整的限定文件名引用。
for
执行指定的命令行,并在后台启动一个带有 %ComSpec% /c
并附加指定命令行的命令进程。这意味着执行后 Windows 安装在驱动器 C:
上:
C:\Windows\System32\cmd.exe /c sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1'"
for
捕获为处理已启动命令进程的 STDOUT 而编写的所有内容。捕获的输出行在开始 cmd.exe
终止后由 for
逐行处理。启动的 cmd.exe
或 Windows 命令处理器在后台执行的 commands/executables 处理 STDERR 的错误消息被重定向到处理 命令进程的 STDERR 处理批处理文件并打印到控制台。但是没有控制台window就运行一个批处理文件作为计划任务。因此在这种情况下无法看到错误消息。
可以在此处轻松修改 for
命令行,以便将错误消息也写入 C:\Apps\Debug.log
。
FOR /F "tokens=* USEBACKQ" %%F IN (`sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1' 2^>^&1"`) DO (
Microsoft 文章 Using command redirection operators 解释了 2>&1
。 >
和 &
这两个运算符必须使用 ^
进行转义,以便在 Windows 命令处理器解析 for
命令行之前解释为文字字符,然后最终执行 for
使用指定的命令行执行下一个 %ComSpec% /c
,其中 2^>^&1
已经更改为 2>&1
.
日志文件 C:\App\Debug.log
是否包含此修改后的两行?
'sqlcmd' is not recognized as an internal or external command,
operable program or batch file.
是的,然后启动 cmd.exe
没有找到文件名为 sqlcmd
的可执行文件。最好的解决方案是使用完整的限定文件名引用此可执行文件。另见:
否则 sqlcmd
可能会输出一条错误消息,现在应该也在日志文件中 C:\App\Debug.log
。
也可以使用以下命令行让后台cmd.exe
将错误信息写入单独的错误日志文件C:\App\Error.log
:
FOR /F "tokens=* USEBACKQ" %%F IN (`sqlcmd -j -S DOMAIN\SQLSERVER -U username -P password -d DBNAME -Q "UPDATE [DBNAME].[dbo].[table1] SET ColOne='V1_OFF' WHERE ColOne='V1'" 2^>C:\App\Error.log`) DO (
"tokens=* usebackq"
导致首先删除非空行上的所有前导水平制表符和正常 spaces for
,然后检查剩余行是否以 [=47= 开头] 在这种情况下,该行也将被忽略,并最终将捕获的不以 ;
开头且前导 tabs/spaces 删除的行分配给循环变量 F
以进行进一步处理。
更好的做法是使用不包含在双引号中的选项 usebackq^ delims^=^ eol^=
,这需要转义两个 space 和两个带脱字符 ^
的等号,以将其解释为文字在执行 for
之前解析命令行时 cmd.exe
的字符。由于定义了一个空的分隔符列表,所以使用 delims=
完成了行拆分行为。由于行尾字符从默认 ;
修改为无字符,因此不再忽略除空行之外的任何行。
最后,echo
行上的 space 留给重定向运算符 >>
也由 echo
输出,因此写为尾随 space到日志文件中。因此,在打印将 echo
重定向到文件的行时,不应将 space 留给 >
或 >>
。但是必须注意省略留给重定向运算符的 space 字符。留给重定向运算符的 word 不应该是 1
, 2
, ..., 9
因为这会导致输出重定向到这些编号句柄而不是字符 1
、2
等。因此,如果要将未知文本写入文件,最好先指定重定向运算符 >
或>>
和完整的限定文件名,然后是 echo
命令和要输出的文本。另见:
带有 echo
的三个命令行将用于此批处理文件:
ECHO Disabling the following...>> C:\App\Debug.log
ECHO - V1>> C:\Apps\Debug.log
>>C:\Apps\Debug.log ECHO %%F
following...
和 V1
一样可以安全地正确写入文件。 %%F
可能只是 1
或以 space 和一个数字结尾的字符串,因此最好在最后一个 echo
命令行中首先指定重定向以获取最后由 cmd.exe
命令行 ECHO %%F 1>>C:\Apps\Debug.log
.