停用eol,将delims设置为换行或换行符以启用按行号进行标记化

时间:2018-10-24 14:06:17

标签: batch-file for-loop token newline

前言

  1. 我正在使用批处理来做到这一点
  2. 尽管在这个主题上有很多“相关”的问题,但这个问题是不同的/不是重复的,因为我想标记行而不是“逐行阅读”

我在做什么

我想要一种简单的方法来指定要解析的行,并且我认为最好的方法是使用FOR循环的tokens选项。问题在于,默认情况下,标记由eol设置(默认为换行符)和delims设置(默认为空格)分开。这对于大多数用例来说都很棒,但是我想标记每一行。这将使我能够轻松轻松地完成很多我想做的事情。

我如何尝试过

无论如何,我发现您可以通过在FOR选项中执行eol ^ =来禁用eol字符。问题是我找不到我需要在delims =中指定的实际字符,以将分隔符设置为等于换行符,换行符或仅表示换行符的其他任何字符。我不想简单地逐行处理我想标记每一行。这很重要,因为这样的问题:

New line as a delimeter of FOR loop

这:

What delimiter to use in FOR loop for reading lines?

不适用。此外,我发现了这个问题,但答案实际上并不符合我的需求。

https://www.dostips.com/forum/viewtopic.php?t=6471

之所以不适用,是因为那些人​​询问要逐行读取文件。我在问关于标记每一行。这是不同的,因为逐行读取可以通过禁用delims和eol或将delims设置为找到的第一个字符/将其设置为空来完成(执行“ delims =”)。这不是我想要的,因为我想启用delim,并且希望IT拆分每行,而不是eol拆分每行。

为什么要这么做?

有些背景知识,我打算使用skip命令,但是forloop的联机帮助页上说,skip选项仅跳到指定的行,不允许您说;跳过3行,阅读一行,然后跳过更多行,或按行号跳过。我可以只使用一个forloop来提取一行,也可以使用更多的forloop或使用计数器和嵌套的for循环来做一些复杂的事情,但是如果我可以简单地对每一行进行标记的话,会容易得多。

这就是我想要的

有效地是我想要的:

FOR /F "tokens=1,3 delims=<linefeed go here> eol^=" %%A IN ('command 
that prints out multiple lines') DO (echo %%A)

它将回显命令输出的第一行和第三行,如下所示:

<command output line 1>
<command output line 3>

(如果您有一个简单命令的好例子,该命令至少打印出三行,我愿意对其进行编辑以更直接地显示我的意思,但我想您会明白的。) / p>

所以我的问题基本上是这样的:

A:是否可以像这样完成行的标记化(即指定要由标记号读取的行号) B:如果A为true,那么我需要用delims换行的实际字符是什么?在我搜索过的所有地方,人们似乎都说不是应该那样做,但是由于他们提出的问题略有不同,因此这里并不适用。我可以使用ASCII码吗?是否可以在禁用eol的情况下将其设置为换行?

我见过有人使用:

set $lf=^
delims^=^%$lf%%$lf%^

在DOStips论坛上,我不太明白那里发生了什么。他们是否将换行符设置为其他字符?看来他们正在尝试同时使用和禁用delims,这对我来说毫无意义。

额外:如果我错误地禁止上线,或者其他原因会干扰我目前的做法,请告诉我,如果您能将我指向帮助页或我很乐意告诉自己,以便不占用您的时间,时间。

为什么如此重要?

因为它使读取文件和仅从命令输出中仅捕获想要的行而不是进行防御,标记化您甚至不需要的行和空格以及仅捕获您要做的行变得更加容易。这样,我就可以直接说(我只想要这些行),并且在我完成所有需要的操作后,甚至不需要goto或任何怪异的东西就可以脱离forloop。

一个完美的例子是考虑下面的文本行,说我只想从此“文件”中获取e和i。

  1. a b c
  2. d e f
  3. g h i
  4. j k l

要定期执行此操作,我需要跳过第一行,开始令牌化,获取第二个令牌,获取第六个令牌,然后使用goto中断。我不想必须逐个令牌地计算令牌,也不需要在完成后使用goto跳出循环。我只想说“抢第二行和第三行,对它们稍有不同”。没有傻瓜,没有计数令牌,没有混乱

更新,我尝试了剂量提示建议

顺便说一句,这只是试图在我的本地计算机上获取所有portopening设置(我正在测试colleauge的批处理脚本)

echo Portopenings check
set $lf=^
FOR /F "tokens=* delims^=^%$lf%%$lf%^ eol^=" %%A IN ('netsh firewall show 
portopening') DO (echo %%A)

但是由于某种原因,它没有抛出任何错误,也没有输出任何东西。我希望它输出一些包含我的portopening设置的行。在没有delims和eol选项的情况下在forloop中运行命令可以正常工作。这个:

FOR /F "tokens=*" %%A IN ('netsh firewall show portopening') DO (echo %%A)

更新2

从发现了这个怪物 How can you echo a newline in batch files?

set NLM=^


set NL=^^^%NLM%%NLM%^%NLM%%NLM%
echo There should be a newline%NL%inserted here.

这实际上可以按预期工作(请确保保留间距,由于某种原因使上面的内容无法正常工作,而打印There should be a newline^^^^inserted here)。唯一的问题是,我似乎无法使其真正在FOR循环中工作。我一直在尝试:

FOR /F "tokens=* delims=%NL% eol^=" %%A IN ('netsh firewall show 
portopening') DO (echo %%A)

有变化,但似乎根本没有任何作用。它只是说eol^=" was not expected,如果我删除了"",它将说syntax incorrect。我知道我需要引号,我很确定eol^=语法是正确的,因此我认为它与这些内容没有直接关系。我认为delims发生了一些奇怪的事情,导致无法反映实际问题的严重错误。

更新3,兔子洞

请注意,您需要上面的NL或NLM定义才能尝试运行它们(尽管它们不起作用) 我尝试过:

  for /F "tokens^=1,2 delims^= eol^=^^!NLM^^!" %%i in ('netsh firewall show 
  portopening') do (echo %%i)

  for /F ^"tokens^=1,2 delims^=!NLM! eol^=^" %%i in ('netsh firewall show 
  portopening') do (echo %%i)

  for /F "tokens=1,2 delims^=!NLM! eol=" %%i in ('netsh firewall show 
  portopening') do (echo %%i)

  for /F "tokens=1,2 delims^=!NLM!" %%i in ('netsh firewall show 
  portopening') do (echo %%i)

  for /F "tokens=1,2 delims= eol=" %%i in ('netsh firewall show 
  portopening') do (echo %%i)

  for /F "delims=!NLM! eol=" %%i in ('netsh firewall show 
  portopening') do (echo %%i)

  for /F "delims^=!NLM! eol=" %%i in ('netsh firewall show 
  portopening') do (echo %%i)

  for /F "delims^=!NLM! eol^=" %%i in ('netsh firewall show 
  portopening') do (echo %%i)

  for /F ^"delims^=!NLM! eol^=^" %%i in ('netsh firewall show 
  portopening') do (echo %%i)

  for /F ^"delims^=^!NLM^! eol^=^" %%i in ('netsh firewall show 
  portopening') do (echo %%i)

和其他方法,我也使用%NLM%尝试了上述所有方法 并且我尝试将!NL!%NL%用于所有这些。我尝试省略选项,重新组合选项,重新排序选项,转义,不转义以及所有其他FUN组合。大多数会导致语法错误,有些会使用tokens = *打印整个输出,有些会打印一些毫无意义的东西(基于奇怪的未标记列的输出,其中的拆分没有意义),但似乎永远不会只打印某些内容行的令牌。此外,手册页还说eol的默认值为;,它是用来确定哪些行是注释,而不是结束一行。我只想让定界符成为换行符,并使其他所有操作都不做。我只想按输出的每一行来标记,或者有其他一些简单的方法来仅捕获特定行。 Skip选项几乎没有用,除非我只想抓住一行(它们确实应该扩展了该功能)。我只是无法绕过输出:TO ME eol=<whatever>应该工作。我什至尝试将其设置为Q@-只是为了尝试并不要分割行,但是出于某些原因,命令行讨厌eol^=并说可怕的语法。如果我使用delimseol但不使用tokens,即使是陌生人,我也可以省略"",但是如果使用令牌,它将永远都不能使用引号。更糟糕的是,我找不到确切的信息说明如何真正逃避一切以实现我的需求。我所知道的是eol^=是“禁用” eol的“””“应该”””””。我不知道它是如何工作的,是否有效的,或者是其他任何方法,但是在尝试了上述方法之后,我认为关于其他问题的本主题答案的90%肯定是完全错误的。甚至更陌生的是,我可以在回显语句中使用!NL!%NL%,而且效果很好。尝试将其用于delims无效。尝试使用原始^字符或转义的^字符也不起作用。我什至不知道克拉是否是换行符/换行符,我只是希望该字符是delims,以便每个令牌都为一行。 Mybe delims和令牌无关,但我认为它们是相关的。我认为令牌是由delims定义的,因为delims按DEFAULT是一个空格。随时教育我,我要在爆炸前吃午饭。

1 个答案:

答案 0 :(得分:3)

嗯...与此问题有关的几点。

首先要注意的是:for /F命令先 不能读取所有文件行,并将它们存储在“缓冲区”类中,然后 then 根据LF字符标记缓冲区。 for /F命令无法通过这种方式工作。

请仔细阅读您自己写的这句话:“另外,手册页还说eol的默认值是;用来确定哪些行是注释而不是结束行”。 eol选项定义在行首出现时导致忽略行的字符。期间。

现在替代:

set "lines=1 3"
FOR /F "tokens=1* delims=:" %%A IN ('command prints lines ^| findstr /N "^"') DO (
   FOR /F "tokens=1*" %%X in ("!lines!") do (
      IF "%%A" EQU "%%X" (
         echo %%B
         set "lines=%%Y"
      )
   )
)

基于您的示例的工作代码:

@echo off
setlocal EnableDelayedExpansion

set "lines=2 3"
set "selected="
FOR /F "tokens=1* delims=:" %%A IN ('type test.txt ^| findstr /N "^"') DO (
   FOR /F "tokens=1*" %%X in ("!lines!") do (
      IF "%%A" EQU "%%X" (
         set "selected=!selected! %%B"
         set "lines=%%Y"
      )
   )
)

for /F "tokens=2,6" %%A in ("%selected%") do (
   echo Token 2: "%%A"
   echo Token 6: "%%B"
)

test.txt:

a b c
d e f
g h i
j k l

输出:

Token 2: "e"
Token 6: "i"