DOS 批处理 FOR 循环与 FIND.exe 正在删除空白行?

发布于 2024-12-25 22:35:02 字数 255 浏览 2 评论 0原文

即使我使用 TYPE.exe 命令转换文件以确保文件是 ASCII 以便 FIND 命令与文件兼容,此 DOS 批处理脚本也会删除文件中的空行并且不显示文件中的空行。谁能告诉我如何使这个脚本包含空行?

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

This DOS batch script is stripping out the blank lines and not showing the blank lines in the file even though I am using the TYPE.exe command to convert the file to make sure the file is ASCII so that the FIND command is compatible with the file. Can anyone tell me how to make this script include blank lines?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

始终不够爱げ你 2025-01-01 22:35:02

这是 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 确实会丢弃长行。

如果文件可能包含以分隔符开头的行,则需要保留带有行号前缀的整行,然后使用搜索和替换来删除行前缀。当将 %%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) 行必须以结束; (如果进行 TYPE 文件转换,这不会成为问题)

2) 行的长度必须 <= 1021 字节(忽略

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"

That is the designed behavior of FOR /F - it never returns blank lines. The work around is to use FIND or FINDSTR to prefix the line with the line number. If you can guarantee no lines start with the line number delimiter, then you simply set the appropriate delimiter and keep tokens 1* but use only the 2nd token.

::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"

I prefer FINDSTR - it is more reliable. For example, FIND can truncate long lines - FINDSTR does not as long as it reads directly from a file. FINDSTR does drop long lines when reading from stdin via pipe or redirection.

If the file may contain lines that start with the delimiter, then you need to preserve the entire line with the line number prefix, and then use search and replace to remove the line prefix. You probably want delayed expansion off when transferring the %%A to an environment variable, otherwise any ! will be corrupted. But later within the loop you need delayed expansion to do the search and replace.

::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"

If you don't need to worry about converting the file to ASCII, then it is more efficient to drop the pipe and let FIND or FINDSTR open the file specified as an argument, or via redirection.

There is another work around that completely bypasses FOR /F during the read process. It looks odd, but it is more efficient. There are no restrictions with using delayed expansion, but unfortunately it has other limitations.

1) lines must be terminated by <CR><LF> (this will not be a problem if you do the TYPE file conversion)

2) lines must be <= 1021 bytes long (disregarding the <CR><LF>)

3) any trailing control characters are stripped from each line.

4) it must read from a file - you can't use a pipe. So in your case you will need to use a temp file to do your to ASCII conversion.

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"
静若繁花 2025-01-01 22:35:02

我编写了一个非常简单的程序,当用于此目的时,它可以替代 FIND 和 FINDSTR 命令。我的程序叫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 子例程中的代码创建一个名为 pipeline.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 版本中运行。

安东尼奥

I wrote a very simple program that may serve as replacement for FIND and FINDSTR commands when they are used for this purpose. My program is called PIPE.COM and it just insert a blank space in empty lines, so all the lines may be directly processed by FOR command with no further adjustments (as long as the inserted space don't cares). Here it is:

@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

EDIT: Addendum as answer to new comment

The code at :DefinePipe subroutine create a 88 bytes program called pipe.com, that basically do a process equivalent to this pseudo-Batch code:

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

This way, empty lines in the input file are changed by lines with one space, so FOR /F command not longer omit they. This works "as long as the inserted space don't cares" as I said in my answer.

Note that the pipe.com program does not work in 64-bits Windows versions.

Antonio

国际总奸 2025-01-01 22:35:02

输出行包括空行

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

将代码保存为批处理文件,例如 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 > destination.txt

showall source.txt | FIND "string"

一个奇怪的地方是包含'^<' (重定向)而不是仅仅执行以下操作:

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

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

Output lines including blank lines

Here's a method I developed for my own use.

Save the code as a batch file say, SHOWALL.BAT and pass the source file as a command line parameter.

Output can be redirected or piped.

@echo off

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

exit /b

EXAMPLES:

showall source.txt

showall source.txt >destination.txt

showall source.txt | FIND "string"

An oddity is the inclusion of the '^<' (redirection) as opposed to just doing the following:

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

By omitting the redirection, a leading blank line is output.

喜你已久 2025-01-01 22:35:02

感谢 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
)

Thanks to dbenham, this works, although it is slightly different than his suggestion:

::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
)
幽蝶幻影 2025-01-01 22:35:02

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

   编辑:根据Jeb下面的评论,似乎 ping 命令,至少在 Windows XP 中是
   导致 for /f 产生 而不是空行(如果有人具体知道原因,会
如果他们可以更新此答案或评论,我们将不胜感激)。

   作为解决方法,似乎是第二个默认分隔标记(示例中的 / %%b
   返回为空白,这适用于我通过“父级”消除空白行的情况
   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 上看到的,这是唯一的三个版本我可以随时访问的 Windows 服务包:

Windows XP Pro SP3

Windows 7 企业版 SP1

Windows Server 2008 R2 企业版 SP1

As mentioned in this answer to the above question, it doesn't seem that lines are skipped by default using for /f in (at least) Windows XP (Community - Please update this answer by testing the below batch commands on your version & service pack of Windows).

   EDIT: Per Jeb's comment below, it seems that the ping command, in at least Windows XP, is
   causing for /f to produce <CR>'s instead of blank lines (If someone knows specifically why, would
   appreciate it if they could update this answer or comment).

   As a workaround, it seems that the second default delimited token (<space> / %%b in the example)
   returns as blank, which worked for my situation of eliminating the blank lines by way of an "parent"
   if conditional on the second token at the start of the for /f, like this:

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

Using the below code:

@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

.... the following is what I see on Windows XP, Windows 7 and Windows 2008, being the only three versions & service packs of Windows I have ready access to:

Windows XP Pro SP3

Windows 7 Enterprise SP1

Windows Server 2008 R2 Enterprise SP1

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文