是否可以在CMD中使用两个空格作为单个分隔符?

时间:2012-08-14 16:07:36

标签: for-loop cmd wmic

我认为这不可能,但我希望能够做到这一点,或者可能使用另一种方法......

我有一个批处理文件;

for /f "usebackq tokens=*" %%a in (`wmic process get description, commandline`) do (
*Some Code*
)

我需要能够从每一行中获取两个答案,并单独使用它们(基本上,使用描述来检查进程是否正在运行,然后在我杀死进程并完成一些文件清理之后work,重新加载原始进程,包括任何命令行参数。

我可能需要结束/重新打开的流程输出的一个示例可能是;

"C:\some folder\some other folder\some_application" -cmd_parameter                process_name.exe

请注意,描述由多个空格明确定义。


有没有办法说

for /f "tokens=* delims=  "    <--(The delims is TWO spaces, not space OR space)

另一种可能更好的方法是使用特殊字符(即从未在过程或路径中使用过的那个)重新创建多个空格的所有实例,然后将其用作我的分隔符......虽然我不喜欢我知道这是否可能..

我也可以使用任何替代方法,只要我可以获取进程名称(检查预定义的进程列表,以及exe的完整路径,以及给定的任何命令行参数。) / p>

全部谢谢

3 个答案:

答案 0 :(得分:2)

直接回答你的问题:不,你不能指定2个空格作为分隔符。您可以使用SET搜索和替换将2个空格更改为某个唯一字符,但确定一个永远不会出现在您的描述或命令行中的唯一字符更容易说完。

更好的选择是将WMIC的输出格式更改为LIST - 每行一个值propertyName=Value。每个属性值都可以存储在变量中,然后当记录进程的最后一个属性时,可以使用变量值进行操作。 WMIC输出使用Unicode,这会导致CarriageReturn字符附加到每个变量赋值的末尾。必须剥离CarriageReturn以获得正确的结果。

@echo off
setlocal
for /f "tokens=1* delims==" %%A in ('"wmic process get description, commandline /format:list"') do (
  if "%%A"=="CommandLine" (
    set "cmd=%%B"
  ) else if "%%A"=="Description" (
    set "desc=%%B"
    setlocal enableDelayedExpansion
    set "desc=!desc:~0,-1!"
    set "cmd=!cmd:~0,-1!"
    echo(
    echo Do whatever you need to do with the description and command line.
    echo description=!desc!
    echo command line=!cmd!
    endlocal
  )
)

您需要注意一些事项。

1)您可以为同一图像名称设置多个进程。如果您通过图像名称(描述)终止进程,则将删除所有进程。如果你也根据命令行重新启动它,那么当下一个具有相同名称的进程被终止时它将再次被杀死。最好通过进程ID终止进程。

2)如果您知道过程的图像名称(描述),则可以使用WMIC WHERE子句限制输出。

3)WMIC报告的命令行并不总是可靠的。该过程能够修改报告为命令行的值。

这是一个检索特定描述的进程ID和命令行的解决方案 编辑 - 我修改了以下代码

@echo off
setlocal
for /f "tokens=1* delims==" %%A in ('"wmic process where description='MyApp.exe' get processId, commandline /format:list"') do (
  if "%%A"=="CommandLine" (
    set "cmd=%%B"
  ) else if "%%A"=="ProcessId" (
    set "id=%%B"
    setlocal enableDelayedExpansion
    set "id=!id:~0,-1!"
    set "cmd=!cmd:~0,-1!"
    echo(
    echo Do whatever you need to do with the process id and command line.
    echo process Id=!id!
    echo command line=!cmd!
    endlocal
  )
)

注意 - WMIC WHERE子句使用SQL语法。它可以使用AND和OR条件变得复杂,并且它支持使用%和_作为通配符的LIKE运算符。我相信整个表达式在变得复杂时需要用双引号括起来。

答案 1 :(得分:1)

前言

我想为以后的读者添加此内容,因为我遇到了这个问题,自己解决了这个问题,我认为这仅对演示如何完成此操作很有用。首先,dbenham的答案绝对正确,即“不,您不能指定2个空格作为分隔符。” 。由于您不能直接使用批处理for循环来执行此操作,因此您可以简单地自己做一个工作。同样,dbenham正确地说

  

“您可以使用SET搜索并替换以将2个空格更改为某个唯一字符”

多数民众赞成在某种程度上类似于我所做的事情(有所不同),但出于完整性考虑,我认为将其记录在案是很好的。问题是,仅将所有出现的双精度空格设置为其他字符并不能总是解决问题。有时我们有两个以上的空格,而我们真正想要的是用多个空格来分隔字符串。我在这里试图解决的问题更像是这样(来自OP)Ricky Payne

  

”另一种可能更好的方法是用特殊字符替换多个空格的所有实例(即一个从未使用过的实例)   在过程或路径中),然后将其用作我的参量...尽管我   不知道那是否有可能。“

答案是,这是可能的,而且一点也不困难。您所需要做的就是

A。遍历字符串的每个字符

B。区分单个和两个(或更多)空间

C。遇到双空格时打开标志

D。将双精度(或更多)空格转换为可以分隔的特殊字符或字符序列。

代码

要做到这一点,我编写了自己的代码(为清楚起见进行了编辑):

FOR /F "tokens=* delims=*" %%G IN ('<command with one line output>') DO (SET 
"LineString=%%G")
SET /A "tempindex=0"
:LineStringFOR
    SET "currchar=!LineString:~%tempindex%,1!"
    IF "!currchar!"=="" (goto :LineStringFOREND)
    SET /A "tempindex=!tempindex!+1"
    SET /A "BeforeSpacePosition=!tempindex!"
    SET /A "AfterSpacePosition=!tempindex!+1"
    IF NOT "!LineString:~%BeforeSpacePosition%,2!"=="  " (goto :LineStringFOR)
    :LineStringSUBFOR
        IF "!LineString:~%BeforeSpacePosition%,2!"=="  " (
        SET LineString=!LineString:~0,%BeforeSpacePosition%!!LineString:~%AfterSpacePosition%!
        GOTO :LineStringSUBFOR
        ) ELSE (
        SET LineString=!LineString:~0,%BeforeSpacePosition%!;!LineString:~%AfterSpacePosition%!
        GOTO :LineStringSUBFOREND
        )
    :LineStringSUBFOREND
    GOTO :LineStringFOR
:LineStringFOREND
ECHO Final Result is "!LineString!"

因此,如果您的输入(FOR中命令的输出,或者您可以更改FOR循环以接收字符串)是

“ a b c a b c”

输出应采用以下格式:

“ a; b; c; a b c”

我已经用自己的代码对此进行了测试。但是,在这里为我的答案,我删除了所有注释,并更改了一些变量名称以使其更加清晰。如果在您输入命令后此代码不起作用,请随时告诉我,我将对其进行更新,但它应该起作用。在此处进行格式化可能会阻止直接复制粘贴。

只是为了显示实际情况

程序流程基本上是这样的:

FOR each character
:TOP
grab the next character
set a variable to the current index
set another variable to the next index
IF this or the next character are not spaces, goto the TOP
:Check for 2 spaces again
IF this and the next character are both spaces then
    get the string up to (but not including) the current index AS A
    get the string after the current index AS B
    set the string to A+B
    goto Check for 2 spaces again
ELSE we have turned the double or more space into one space
    get the string up to (but not including) the current index AS A
    get the string after the current index AS B
    set the string to A + <char sequence of choice for delimiting> + B
goto TOP to grab the next character
After all characters are looped over
RETURN the string here (or echo it out like I did)

额外

dbenham在他对这种方法的回答中说:

  

“您可以使用SET搜索并替换以将2个空格更改为一些   唯一字符,但确定一个永远不会出现的唯一字符   出现在您的描述或命令行中说起来容易做起来就容易。”

虽然过去可能是这样,但我大喊(如果我在其他情况下错了,至少可以用我的方法纠正我),实际上您可以使用定界符,该定界符绝对不会出现在您的输入中。这是通过使用多字符定界符来实现的。这不允许您使用标准的FOR循环,但是您可以非常轻松地手动执行此操作。此处对此进行了更深入的描述:

"delims=#+#" - more then 1 character as delimiter

答案 2 :(得分:1)

好线程!

这让我开始思考,于是我想出了一个稍微偏斜的解决方案,该解决方案可能对某人像对我一样有效。

由于最初的问题是关于WMIC命令的,并且输出可以是CSV格式,为什么不只通过使用/ format:csv开关并将逗号设置为定界符并合并“ usebackq”来规避空间处理?

当然,如果来自WMIC的数据本身带有逗号,但在我只需要BootOptionOnWatchDog状态的情况下是完美的,则这可能不起作用

看起来像这样:

FOR /F "usebackq skip=1 tokens=1-31 delims=," %a IN (`%windir%\system32\wbem\wmic computersystem list /format:csv`) DO echo %f

返回:

BootOptionOnWatchDog
Normal boot

我以'skip = 2'结尾,它将返回“ Normal Boot”(正常启动)

顺便说一句,不要经常在这里发帖,因此以客人身份发贴,但请谨慎地将其放在此处,因为正是这篇帖子帮助我得出了上面的答案。

欢呼 -steve(NZ)