2

我想用 FINDSTR /R 匹配以下文本的所有行

LABO_A =
  (DESCRIPTION =
      (ADDRESS = (PROTOCOL = TCP)(HOST = host01)(PORT = 1521))
    (CONNECT_DATA =
      (SERVICE_NAME = LABO)
    )
  )

我已经尝试过Windows FINDSTR 命令有哪些未记录的功能和限制? 特别是“跨换行符搜索”部分。但不幸的是,它没有奏效。

我的方法如下:

SETLOCAL
set LF=^


FOR /F %%A IN ('COPY /Z "%~dpf0" NUL') DO SET "CR=%%A"

SETLOCAL enableDelayedExpansion
FINDSTR /R "LABO_A.=.!CR!*!LF!.*(DESCRIPTION.=.!CR!*!LF!.*(ADDRESS.=.(PROTOCOL.=.TCP)(HOST.=.host01)(PORT.=.1521))!CR!*!LF!.*(CONNECT_DATA.=!CR!*!LF!.*(SERVICE_NAME.=.LABO)!CR!*!LF!.*)!CR!*!LF!.*)" %FINDPATH%

我错过了什么吗?还是批处理正则表达式根本不足以实现这一点?

解决方案: @dbenham 的方法让我重新考虑我的正则表达式字符串。所以我将其编辑为

FINDSTR /R /C:"LABO_A =!CR!*!LF!.*(DESCRIPTION =!CR!*!LF!.*(ADDRESS = (PROTOCOL = TCP)(HOST = host01)(PORT = 1521))!CR!*!LF!.*(CONNECT_DATA =!CR!*!LF!.*(SERVICE_NAME = LABO)!CR!*!LF!.*)!CR!*!LF!.*)" %FINDPATH% > NUL

我删除了一些不必要的空格并调整了 FINDSTR 的参数。

现在它起作用了。

4

3 回答 3

2

你的正则表达式是错误的。您的源代码行在 . 之后立即结束=,但.您的正则表达式中的额外内容正在 . 之后寻找额外的字符=

在我看来,您正在使用它.来表示空白。我认为您最好使用实际空间,但是您需要该/C选项。

以下成功匹配行。

@echo off
SETLOCAL
set LF=^


FOR /F %%A IN ('COPY /Z "%~dpf0" NUL') DO SET "CR=%%A"

SETLOCAL enableDelayedExpansion
FINDSTR /R /C:"LABO_A =!CR!*!LF! *(DESCRIPTION =!CR!*!LF! *(ADDRESS = (PROTOCOL = TCP)(HOST = host01)(PORT = 1521))!CR!*!LF! *(CONNECT_DATA =!CR!*!LF! *(SERVICE_NAME = LABO)!CR!*!LF! *)!CR!*!LF! *)" test.txt

请注意,即使正则表达式中的所有行都匹配,也只会打印匹配集的第一行。

我怀疑您的配置文件中不需要换行符。这是另一个变体,它允许在空白处进行更多变体。

@echo off
setlocal enableDelayedExpansion
set LF=^


FOR /F %%A IN ('COPY /Z "%~dpf0" NUL') DO SET "CR=%%A"
set "ws=[ !cr!!lf!]*"

FINDSTR /RX /C:"LABO_A =!ws!(DESCRIPTION =!ws!(ADDRESS = (PROTOCOL = TCP)(HOST = host01)(PORT = 1521))!ws!(CONNECT_DATA =!ws!(SERVICE_NAME = LABO)!ws!)!ws!)!ws!" test.txt

我还尝试在我认为可能的每个地方允许空格,但这超出了 FINDSTR 的最大 REGEX 字符串长度。

于 2013-11-08T19:56:39.143 回答
1

从本质上讲,批处理正则表达式不够强大。SED毫无疑问会更好。

尽管如此,这里有一种方法可以检测文件中是否出现了一系列行。它有点受限制,但应该足以满足您指定的序列。它假设前导空格不重要。

@ECHO OFF
SETLOCAL enabledelayedexpansion
FOR /f "delims==" %%a IN ('set l_ 2^>nul') DO "SET %%a="
SET /a lines=0
FOR /f "tokens=*" %%a IN (q19859936.txt) DO SET /a lines+=1&SET l_!lines!=%%a

SET hits=0
SET "stop="
FOR /f "tokens=*" %%a IN (q19859936.test) DO (
 SET l_0=%%~a
 CALL :test
 IF DEFINED stop GOTO done
)
:done
IF DEFINED stop (ECHO FOUND ) ELSE (ECHO NOT FOUND)

GOTO :EOF

:test
SET /a hits+=1
ECHO IF NOT "!l_%hits%!"=="%l_0%" 
IF NOT "!l_%hits%!"=="%l_0%" SET hits=0&IF %hits%==1 (GOTO :eof) ELSE (GOTO test)
IF %hits%==%lines% SET stop=Y
GOTO :eof

[编辑代码 20131111T1408Z - 首次FOR拥有tokens=2]

初始FOR确保变量L_*被清除。

该文件q19859936.txt被读取为待检测的行序列数据。

q19859936.test然后检查。每行L_0依次分配,内部子例程:test将检查它是否与预期的下一行匹配。

IF NOT语句很重要 - 并且看似不合逻辑(如果您愿意,您需要添加/i开关以使其不区分大小写......)当批处理解析该行时,%hits%被替换为当时的当前值hitsTHEN行被执行,所以hits如果发现不匹配将被重置为 0。如果HITS计数不是1,则重复测试。这会处理这种情况

matches line 1
matches line 2
matches line 3
matches line 1
matches line 2
matches line 3
matches line 4
matches line 5
matches line 6

当预期“第 4 行”时遇到第二个“第 1 行”。HITS因此更改为 0,但它是4,因此执行返回并以= 1:test重复测试。HITS

另一种方法可能是将行读入另一个数组(例如L#*)并测试L_*匹配L#*的 , 以获取%LINES%条目。在不匹配的情况下,涟漪上升并将下一行读取分配给L#!lines!... 但我后来想到了这一点。可能也更容易和更好 - 我会把它作为练习留给任何可能感兴趣的人。

于 2013-11-08T14:31:02.957 回答
0

如果您在LABO_A参考之后,这将起作用。

它使用一个findrepl.bat从 - https://www.dropbox.com/s/rfdldmcb6vwi9xc/findrepl.bat调用的帮助程序批处理文件

放在findrepl.bat与批处理文件相同的文件夹或路径上。

type "file.txt" | findrepl "^LABO_A =" /e:"^  \)"
于 2013-11-08T16:20:28.907 回答