使用wmic时转义字符串

use*_*903 3 cmd wmic

我正在尝试使用wmic sart一个VLC实例我这样做主要是因为我想捕获创建过程的pid

我知道下面的命令在命令行中工作正常:

C:\PROGRA~1\VideoLAN\VLC_117\vlc.exe rtsp://abcd --sout="#duplicate{dst=display, dst={std{access=file, mux=ps, dst='vlc_117/video.mpg'}}} --rtsp-caching=120 --no-video-title-show"
Run Code Online (Sandbox Code Playgroud)

(其中rtsp:// abcd可以是用于此示例的任何输入文件)

试图通过wmic运行它,以各种不同的尝试作为转义序列(其中下面是一个):

wmic process create 'C:\PROGRA~1\VideoLAN\VLC_117\vlc.exe rtsp://abcd --sout="#duplicate{dst=display, dst={std{access=file, mux=ps, dst='vlc_117/video.mpg'}}} --rtsp-caching=120 --no-video-title-show" '
Run Code Online (Sandbox Code Playgroud)

可靠地给了我同样的错误:

Invalid format.
Hint: <assignlist> = <propertyname>=<propertyvalue> [, <assignlist>].
Run Code Online (Sandbox Code Playgroud)

但是以下内容:

wmic process create 'C:\PROGRA~1\VideoLAN\VLC_117\vlc.exe rtsp://abcd --sout="#duplicate{dst=display} --rtsp-caching=120 --no-video-title-show"'
Run Code Online (Sandbox Code Playgroud)

工作正常 - 除了作为命令它对我没用.所以问题似乎是我原始命令的嵌套卷曲括号部分.

我尝试了各种不同的逃脱角色......到目前为止还没有成功.任何人都可以建议我哪里出错了?

dbe*_*ham 9

在CMD中引用和转义规则很复杂,当你添加WMIC并发症时它们会变得更加疯狂.

WMIC通常可以使用'"作为引号字符.双引号内的双引号可以使用转义\".单引号内的单引号也可以使用转义\',但反斜线似乎不被消耗,所以它似乎是无用的.

CMD仅使用",并且无法"在带引号的字符串中转义.毒的人物,如&,|,<,等不在报价内必须进行转义像^&等.

试图合并WMIC和CMD的引用和转义规则是棘手的.请记住,CMD引用和转义是在WMIC看到命令行之前发生的.

此外,你可以使用PROCESS CALL CREATE而不是PROCESS CREATE.我想这是可能的PROCESS CREATE,但我从来没有见过它是如何完成的.

我不确定我知道你的实际命令行没有使用WMIC.根据您的代码,我假设以下内容可行:

C:\PROGRA~1\VideoLAN\VLC_117\vlc.exe rtsp://abcd --sout="#duplicate{dst=display, dst={std{access=file, mux=ps, dst='vlc_117/video.mpg'}}} --rtsp-caching=120 --no-video-title-show"
Run Code Online (Sandbox Code Playgroud)

如果是这样,那么我相信以下WMIC命令将起作用:

wmic process call create 'C:\PROGRA~1\VideoLAN\VLC_117\vlc.exe rtsp://abcd --sout="#duplicate{dst=display, dst={std{access=file, mux=ps, dst='vlc_117/video.mpg'}}} --rtsp-caching=120 --no-video-title-show"'
Run Code Online (Sandbox Code Playgroud)

WMIC必须在创建为一个连续字符串后才能看到整个命令行.内部单引号'vlc_117/video.mpg'不会导致问题,因为内容中没有空格.添加空格会破坏此解决方案,还需要另一种策略.

如果在exe路径周围使用双引号,则应该能够使用长路径而不是短路径:

wmic process call create '"C:\Program Files\VideoLAN\VLC_117\vlc.exe" rtsp://abcd --sout="#duplicate{dst=display, dst={std{access=file, mux=ps, dst='vlc_117/video.mpg'}}} --rtsp-caching=120 --no-video-title-show"'
Run Code Online (Sandbox Code Playgroud)

您可能希望在批处理文件中的变量中捕获PID,在这种情况下将使用FOR/F命令.这增加了更多的复杂性.必须转义不带引号的CMD令牌分隔符等=,,因为FOR/F引入了额外的解析层.由于额外的解析层,还必须转义未加引号的毒物字符.

for /f "tokens=2 delims=;= " %%N in (
  'wmic process call create '"C:\Program Files\VideoLAN\VLC_117\vlc.exe" rtsp://abcd --sout^="#duplicate{dst=display, dst={std{access=file, mux=ps, dst='vlc_117/video.mpg'}}} --rtsp-caching=120 --no-video-title-show"' ^| find "ProcessId"'
) do set "pid=%%N"
Run Code Online (Sandbox Code Playgroud)

在FOR/F IN()子句中的封闭单引号,因为WMIC曾经看到命令之前,他们被剥夺不会导致出现问题.但是,未引用=--sout=...必须逃脱.

我不能测试上面的任何一个,所以也许没有一个像写的那样工作.但是,我讨论的概念应该仍然有效.

由于引用和转义的层次和复杂性很多,命令行看似微小的变化可能会对解决方案产生重大影响.如果命令不是我解释的那样,那么通过编辑你的问题告诉我正确的命令,我可以尝试调整答案.


更新2014-05-27

我的坏消息.PROCESS CALL CREATE选项要求将完整命令行作为第一个字符串参数,可选地后跟工作目录作为第二个参数.坏消息是参数是用逗号分隔的.您的命令行也有逗号,PROCESS CALL CREATE解析器(无论是什么)似乎不支持命令行中的逗号:(

我试过引用单引号或双引号中的逗号,这没有用.我也试过逃避逗号\.再一次,没有运气.我还搜索了一个解决方案,然后空出来.

我担心可能没有解决方案,除非有可用的VLC语法消除逗号,或者是否有办法将复杂的VLC命令行参数放在某种类型的外部脚本文件中.或者也许其他一些聪明的人发现了逃脱逗号的方法?

以下是一些显示我尝试过的例子.我没有VLC所以我只是用一个ECHO语句替换CMD/C. 尝试使用逗号ECHO失败.

@echo off
:: All of these commands without commas work just fine
wmic process call create 'cmd /c echo hello world^&pause'
wmic process call create 'cmd /c "echo hello world&pause"'
wmic process call create "cmd /c echo hello world&pause"

:: But none of these commands with commas work
wmic process call create 'cmd /c echo hello,goodbye^&pause'
wmic process call create 'cmd /c "echo hello,goodbye&pause"'
wmic process call create "cmd /c echo hello,goodbye&pause"
wmic process call create 'cmd /c echo hello\,goodbye^&pause'
wmic process call create 'cmd /c "echo hello\,goodbye&pause"'
wmic process call create "cmd /c echo hello\,goodbye&pause"
Run Code Online (Sandbox Code Playgroud)

更新2014-12-23:已找到解决方案!

在DosTips上,我们一组为批处理脚本开发了各种方法来确定自己的PID.知道后,可以使用WMIC列出父会话的所有子进程.通过仔细记账,可以可靠地确定每个新创建的子进程的PID.但它需要相当多的代码.如果您的命令行无法通过WMIC PROCESS CALL CREATE(逗号问题)传递,则只需要这样做.

@echo off
setlocal enableDelayedExpansion

:: Get the PID and UID for this batch process
call :getMyPID

:: Initialize an existing PIDs list
set "PIDs= "

:: Get a list of all existing child processes, except for the
:: child CMD.EXE process that was created by this FOR /F loop.
:: This is necessary because the console session that this script
:: is running in might have previously created a child process.
for /f %%A in (
  '2^>nul wmic process where "ParentProcessID=%myPID% and not CommandLine like '%%<%UID%>%%'" get ProcessID'
) do for %%B in (%%A) do set "PIDs=!PIDs!%%B "

:: Create your new process as you normally would.
:: For this demonstration, I will simply create a new CMD.EXE session 
start

:: Get the PID of the newly created child process by getting all child PIDs,
:: except for the child CMD.EXE process that was created by this FOR /F loop.
:: Ignore any PID that already exists in the %PIDs% list. The only PID left
:: is your new process.
for /f %%A in (
  '2^>nul wmic process where "ParentProcessID=%myPID% and not CommandLine like '%%<%UID%>%%'" get ProcessID'
) do for %%B in (%%A) do if "!PIDs: %%B =!" equ "!PIDs!" set "PID=%%B"

:: At this point you could append the new PID to the PIDs list using
::   set "PIDs=!PIDs!%PID% "
:: Then you can repeat the steps of creating a new proces and getting the new PID
::
:: But instead, I will simply show the result and exit
echo new PID=%PID%

exit /b


:getMyPID 
setlocal disableDelayedExpansion

:getLock

:: Establish a nearly unique temp file name using %time%
set "lock=%temp%\%~nx0.%time::=.%.lock"

:: Transform the full path into a UID that can be used in a WMIC query
set "uid=%lock:\=:b%"
set "uid=%uid:,=:c%"
set "uid=%uid:'=:q%"
set "uid=%uid:_=:u%"
setlocal enableDelayedExpansion
set "uid=!uid:%%=:p!"
endlocal & set "uid=%uid%"


:: Establish an exclusive lock on the temp file
:: If this fails, then loop back and try again until success
:: This guaranees no two process will ever have the same UID
2>nul ( 9>"%lock%" (

  %= The FOR /F loops creates a child CMD.EXE process which in turn invokes WMIC.         =%
  %= The child CMD.EXE process contains the WMIC query with the UID in its command line.  =%
  %= The WMIC query identifies the CMD.EXE process with the UID in the command line,      =%
  %= and returns the parent process ID, which happens to be the PID for this batch script =%
  for /f "skip=1" %%A in (
    'wmic process where "name='cmd.exe' and CommandLine like '%%<%uid%>%%'" get ParentProcessID'
  ) do for %%B in (%%A) do set "PID=%%B"
  (call ) %= Guarantee success so we don't accidently loop again =%

))||goto :getLock

:: Delete the temp file
del "%lock%" 2>nul

:: Return the result
( endlocal
  set "myPID=%PID%"
  set "UID=%uid%"
)
exit /b
Run Code Online (Sandbox Code Playgroud)

  • 编辑 - @ user1447903 - 我发现了逗号问题的解决方案.它不漂亮,但它的工作原理! (2认同)