【发布时间】:2016-03-20 07:40:25
【问题描述】:
在 Windows 批处理文件中,当程序调用包含空格和多个选项时,我需要将程序执行的结果检索到变量中。经过多次讨论,使用CALL找到了解决方法:
FOR /F "delims=" %%G IN ('CALL "C:\path with spaces\foo.bat" "blah blah='foobar' blah"') do set foo=%%G
请参阅以下问题以了解更多详细信息并了解上下文:
Retrieve command output to variable when command has spaces
实际上,批处理文件调用 PostgreSQL 9.3,如下所示:
SET PSQL_EXE=C:\Program Files\Foo\Bar\PostgreSQL\9.3\bin\psql.exe
SET FOO=1
REM psql query should result in a 0 or 1 based on the mydbproperty table value
FOR /F %%G IN ('call "%PSQL_EXE%" -U pguser -d MyDB -p %PG_PORT% -c "select string_value from mydb.uri as uri, mydb.property as prop where uri.id = prop.property_uriid and uri.namespace_uri='http://example.com/foo/bar/' and uri.simplename = 'fooBar'" -q -t -w') DO SET FOO=%%G
REM next line doesn't have ERRORLEVEL set
IF !ERRORLEVEL! NEQ 0 EXIT !ERRORLEVEL!
不幸的是,这种格式似乎会产生一个单独的cmd 实例,因此调用 pgsql 时发生的任何错误(例如缺少密码文件)都不会被传回,%ERRORLEVEL% 也不会被设置。具体是 pgsql 打印出来:
psql: fe_sendauth: no password supplied
然而%ERRORLEVEL%(和!ERRORLEVEL!)仍然是0。
有关更多信息,请参阅以下问题:
PSQL Error Level in Batch For Loop
所以现在的问题是如何找出 %ERRORLEVEL%,因为我已经成功获得了psql 的响应。我不想写一些临时文件——我想在内存中做所有事情。
(请注意,是的,我尝试从数据库中查询并存储在FOO 中的值将是0 或1;这并不重要,但它确实使事情变得更多令人困惑。)
我试图通过简单地查看%%G 中返回的内容来测试 Aacini 提出的解决方案:
FOR /F "delims=" %%G IN ('"CMD /V:ON /C CALL "%PSQL_EXE%" -U user -d MyDB -p %PG_PORT% -c "select string_value from mydb.uri as uri, mydb.database_property as prop where uri.id = prop.property_uriid and uri.namespace_uri='http://example.com/foo/bar/' and uri.simplename = 'fooBar'" -q -t -w ^& ECHO !ERRORLEVEL!"') DO (
ECHO %%G
)
因为 psql 找不到密码文件,这将向 stderr 打印一个错误(如预期的那样)并且ECHO 输出0---所以ERRORLEVEL 没有被发送回DO 子句.但是,如果我从FOR 循环中分离出命令并直接运行它,它会显示ERRORLEVEL (2) 就好了!
"%PSQL_EXE%" -U user -d MyDB -p %PG_PORT% -c "select string_value from mydb.uri as uri, mydb.database_property as prop where uri.id = prop.property_uriid and uri.namespace_uri='http://example.com/foo/bar/' and uri.simplename = 'fooBar'" -q -t -w
ECHO !ERRORLEVEL!
更新:在被告知如果我已经打开延迟扩展,我需要逃避转义后,我接受了给定的答案并对其进行了更新,以考虑到我正在调用的程序不会返回一个值,如果它会产生错误。所以这就是我所做的;首先我确保两个变量是未定义的:
SET "var1="
SET "var2="
然后我使用@Aacini 和@jeb 给出的循环,但在循环内我这样做:
if NOT DEFINED var1 (
SET "var1=%%G"
) else (
SET "var2=%%G"
)
然后在循环结束后在循环外:
if DEFINED var2 (
ECHO received value: !var1!
ECHO ERRORLEVEL: !var2!
) ELSE (
ECHO ERRORLEVEL: !var1!
)
这似乎行得通。 (难以置信——什么体操!)
【问题讨论】:
-
在您的原始问题中,我发布了使用短路径的答案。您是否尝试过这个而不是 call 命令?此外,您可能希望看到这个问题:stackoverflow.com/questions/34226971/…
-
请把foo.bat的代码也贴出来。
-
@Squashman,我已经改进了示例以使用我正在使用的实际可执行文件,以及几乎相同的参数。您可以通过将
%PSQL_EXE%更改为指向您选择的某个批处理文件来重现此问题,但请注意路径应包含空格以准确反映问题。 -
我想您在 FOR /F 之前启用了延迟扩展,那么您必须将行修改为
FOR /F ... ('"cmd /V:on .... ^^^& echo ^!ERRORLEVEL^!"') DO ( -
是的,延迟扩展已经开启。我将进一步试验@jeb 的附加信息。
标签: windows batch-file for-loop psql errorlevel