DOS-цикл FOR с FIND.exe удаляет пустые строки? - PullRequest
9 голосов
/ 11 января 2012

Этот пакетный сценарий 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 ]

18 голосов
/ 11 января 2012

Это спроектированное поведение 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 не так долго, как он читает непосредственно из файла. 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) строки должны заканчиваться (это не будет проблемой, если вы выполните преобразование файла ТИПА)

2) строки должны быть <= 1021 байт (без учета <CR>)

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"
2 голосов
/ 11 января 2012

Я написал очень простую программу, которая может служить заменой для команд 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 создает 88-байтовую программус именем pipe.com, который в основном выполняет процесс, эквивалентный этому псевдо-пакетному коду:

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.

Антонио

1 голос
/ 14 января 2012

Выходные строки, включая пустые строки

Вот метод, который я разработал для собственного использования.

Сохраните код в виде пакетного файла, скажем, 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 | НАЙТИ "строку"

Странность - это включение ' ^ <</strong>' (перенаправление), а не просто следующее:

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

Опуская перенаправление, ведущийвыводится пустая строка.

0 голосов
/ 01 февраля 2013

Как уже упоминалось в этом ответе на вышеуказанный вопрос, не похоже, что по умолчанию строки пропускаются с использованием for /f в (как минимум) Windows XP (Сообщество - пожалуйста, обновите этот ответ по тестирование приведенных ниже пакетных команд в вашей версии и пакете обновления Windows).


РЕДАКТИРОВАТЬ: За Jeb комментарий ниже , похоже, что команда ping, по крайней мере Windows XP, является
заставляя for /f выдавать <CR> вместо пустых строк (если кто-то точно знает, почему,
признателен, если они могут обновить этот ответ или комментарий).

В качестве обходного пути кажется, что второй токен по умолчанию с разделителями (<space> / %%b в примере)
возвращается как blank, что сработало для моей ситуации по удалению пустых строк с помощью «родителя»
if условно для второго токена в начале for /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 Enterprise SP1

Windows Server 2008 R2 Enterprise SP1

0 голосов
/ 11 января 2012

Благодаря 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
)
...