使用FIND.exe的DOS批处理FOR循环是否正在删除空白行?

时间:2012-01-10 23:17:27

标签: batch-file dos cmd

这个DOS批处理脚本正在剥离空行并且没有显示文件中的空行,即使我使用TYPE.exe命令转换文件以确保文件是ASCII以便FIND命令兼容与文件。谁能告诉我如何让这个脚本包含空行?

@ECHO off
FOR /F "USEBACKQ tokens=*" %%A IN (`TYPE.exe "build.properties" ^| FIND.exe /V ""`) DO (
  ECHO --%%A--
)
pause

5 个答案:

答案 0 :(得分:18)

这是FOR / F的设计行为 - 它永远不会返回空行。解决方法是使用FIND或FINDSTR在行前面加上行号。如果您可以保证没有行以行号分隔符开头,那么您只需设置适当的分隔符并保持令牌1 *但仅使用第二个令牌。

::preserve blank lines using FIND, assume no line starts with ]
::long lines are truncated
for /f "tokens=1* delims=]" %%A in ('type "file.txt" ^| find /n /v ""') do echo %%B

::preserve blank lines using FINDSTR, assume no line starts with :
::long lines > 8191 bytes are lost
for /f "tokens=1* delims=:" %%A in ('type "file.txt" ^| findstr /n "^"') do echo %%B

::FINDSTR variant that preserves long lines
type "file.txt" > "file.txt.tmp"
for /f "tokens=1* delims=:" %%A in ('findstr /n "^" "file.txt.tmp"') do echo %%B
del "file.txt.tmp"

我更喜欢FINDSTR - 它更可靠。例如,FIND可以截断长行 - 只要直接从文件读取,FINDSTR就不会。当通过管道或重定向从stdin读取时,FINDSTR会丢弃长行。

如果文件可能包含以分隔符开头的行,则需要使用行号前缀保留整行,然后使用search and replace删除行前缀。在将%% A传输到环境变量时,您可能希望延迟扩展,否则任何!将被腐蚀。但是后来在循环中你需要延迟扩展来进行搜索和替换。

::preserve blank lines using FIND, even if a line may start with ]
::long lines are truncated
for /f "delims=" %%A in ('type "file.txt" ^| find /n /v ""') do (
  set "ln=%%A"
  setlocal enableDelayedExpansion
  set "ln=!ln:*]=!"
  echo(!ln!
  endlocal
)

::preserve blank lines using FINDSTR, even if a line may start with :
::long lines >8191 bytes are truncated
for /f "delims=*" %%A in ('type "file.txt" ^| findstr /n "^"') do (
  set "ln=%%A"
  setlocal enableDelayedExpansion
  set "ln=!ln:*:=!"
  echo(!ln!
  endlocal
)

::FINDSTR variant that preserves long lines
type "file.txt" >"file.txt.tmp"
for /f "delims=*" %%A in ('findstr /n "^" "file.txt.tmp"') do (
  set "ln=%%A"
  setlocal enableDelayedExpansion
  set "ln=!ln:*:=!"
  echo(!ln!
  endlocal
)
del "file.txt.tmp"

如果您不需要担心将文件转换为ASCII,那么删除管道并让FIND或FINDSTR打开指定为参数的文件或通过重定向更有效。

还有另一种解决方法是在读取过程中完全绕过FOR / F.它看起来很奇怪,但效率更高。使用延迟扩展没有任何限制,但不幸的是它有其他限制。

1)行必须由< CR>< LF>终止。 (如果你进行TYPE文件转换,这不会有问题)

2)行必须<= 1021字节长(忽略&lt; CR&gt;&lt; LF&gt;)

3)从每一行中删除任何尾随控制字符。

4)它必须从文件中读取 - 您不能使用管道。因此,在您的情况下,您将需要使用临时文件进行ASCII转换。

setlocal enableDelayedExpansion
type "file.txt">"file.txt.tmp"
for /f %%N in ('find /c /v "" ^<"file.txt.tmp"') do set cnt=%%N
<"file.txt.tmp" (
  for /l %%N in (1 1 %cnt%) do(
    set "ln="
    set /p "ln="
    echo(!ln!
  )
)
del "file.txt.tmp"

答案 1 :(得分:2)

我写了一个非常简单的程序,当它们用于此目的时,它可以替代FINDFINDSTR命令。我的程序名为PIPE.COM,它只是在空行中插入一个空格,因此所有行都可以由FOR命令直接处理而无需进一步调整(只要插入的空格不关心) )。这是:

@ECHO off
if not exist pipe.com call :DefinePipe
FOR /F "USEBACKQ delims=" %%A IN (`pipe ^< "build.properties"`) DO (
  ECHO(--%%A--
)
pause
goto :EOF

:DefinePipe
setlocal DisableDelayedExpansion
set pipe=´)€ì!Í!ŠÐŠà€Ä!€ü.t2€ü+u!:æu8²A€ê!´#€ì!Í!².€ê!´#€ì!Í!²+€ê!´#€ì!Í!Šò€Æ!´,€ì!Í!"Àu°´LÍ!ëÒ
setlocal EnableDelayedExpansion
echo !pipe!>pipe.com
exit /B

编辑附录作为新评论的回答

代码:DefinePipe子例程创建一个名为pipe.com的88字节程序,它基本上做了一个等同于这个伪批处理代码的进程:

set "space= "
set line=
:nextChar
   rem Read just ONE character
   set /PC char=
   if %char% neq %NewLine% (
      rem Join new char to current line
      set line=%line%%char%
   ) else (
      rem End of line detected
      if defined line (
         rem Show current line
         echo %line%
         set line=
      ) else (
         rem Empty line: change it by one space
         echo %space%
      )
   )
goto nextChar

这样,输入文件中的空行被一行空格改变,因此FOR / F命令不再省略它们。正如我在回答中所说的那样,“只要插入的空间不关心”就可以了。

请注意,pipe.com程序在64位Windows版本中不起作用。

安东尼奥

答案 2 :(得分:1)

输出行包括空行

这是我为自己开发的方法。

将代码保存为批处理文件,例如 SHOWALL.BAT ,并将源文件作为命令行参数传递。

可以重定向或管道输出。

@echo off

for /f "tokens=1,* delims=]" %%a in ('find /n /v "" ^< "%~1"') do echo.%%ba

exit /b

<强>实施例

showall source.txt

showall source.txt &gt; destination.txt

showall source.txt | 查找“字符串”

奇怪的是包含' ^&lt; '(重定向),而不是仅执行以下操作:

for /f "tokens=1,* delims=]" %%a in ('find /n /v "" "%~1"') do echo.%%ba

通过省略重定向,输出前导空行。

答案 3 :(得分:0)

感谢dbenham,虽然与他的建议略有不同,但仍有效:

::preserve blank lines using FIND, no limitations
for /f "USEBACKQ delims=" %%A in (`type "file.properties" ^| find /V /N ""`) do (
  set "ln=%%A"
  setlocal enableDelayedExpansion
  set "ln=!ln:*]=!"
  echo(!ln!
  endlocal
)

答案 4 :(得分:0)

正如this对上述问题的回答中提到的那样,默认情况下,使用for /f(至少)Windows XP中的行似乎没有跳过(社区 - 请更新此通过在Windows的版本和服务包上测试以下批处理命令来回答。


编辑:根据Jebcomment belowping命令(至少Windows XP)似乎是 导致for /f生成<CR>而不是空行(如果有人特别知道原因,那么会 如果他们能够更新此答案或评论,请表示赞赏。)

作为解决方法,似乎第二个默认分隔标记(示例中为<space> / %%b
返回blank,这适用于我通过“父”清除空行的情况 iffor /f开头的第二个令牌为条件,如下所示:

   for /f "tokens=1,2*" %%a in ('ping -n 1 google.com') do (
      if not "x%%b"=="x" (
         {do things with non-blank lines}
      )
   )



使用以下代码:

@echo off
systeminfo | findstr /b /c:"OS Name" /c:"OS Version" 
echo.&echo.
ping -n 1 google.com
echo.&echo.
for /f %%a in ('ping -n 1 google.com') do ( echo "%%a" )
echo.&echo.&echo --------------&echo.&echo.
find /?
echo.&echo.
for /f %%a in ('find /?') do ( echo "%%a" )
echo.&echo.
pause

....以下是我在Windows XP,Windows 7和Windows 2008上看到的,是仅有的三个版本&amp; Windows的服务包我可以随时访问:

Windows XP Pro SP3

Windows 7 Enterprise SP1

Windows Server 2008 R2 Enterprise SP1