Эхо-файл новой строки в конце - PullRequest
0 голосов
/ 28 декабря 2018

Это мой скрипт для добавления данных в определенный файл:

@echo off

FIND /C /I "foo" %WINDIR%\system32\drivers\etc\hosts
IF %ERRORLEVEL% NEQ 0 ECHO ^8.8.8.8 foo>>%WINDIR%\System32\drivers\etc\hosts

Когда файл содержит новую строку в конце, он работает правильно:

from:

data
 

до:

data
8.8.8.8 foo

Но когда файл не содержит новой строки в конце, я получаю соединенные строки:

от:

data

to:

data8.8.8.8 foo

Что мне нужно сделать, чтобы мой код работал правильно для файлов с AND без перевода строки в конце?

Ответы [ 4 ]

0 голосов
/ 29 декабря 2018

FINDSTR имеет странную причуду, что он добавляет \r\n (возврат каретки, перевод строки) к вводу по конвейеру, если поток ввода не заканчивается \n (перевод строки).См. Канал и перенаправленный вход может иметь <CR><LF> добавленный раздел в https://stackoverflow.com/a/8844873/1012053 для получения дополнительной информации.

Вы можете использовать этот трюк для выборочного добавленияпропущенная новая строка тогда и только тогда, когда это необходимо.

@echo off
setlocal
set "file=%windir%\system32\drivers\etc\hosts"
findstr /m /i "foo" "%file%" >nul || (
  (
    type "%file%" | findstr "^"
    echo 8.8.8.8 foo
  ) >"%file%.new"
  move /y "%file%.new" "%file%"
)

Я решил использовать FINDSTR вместо FIND для поиска foo, и я использую || условное выполнение при ошибке вместо использованияIF проверка операторов ERRORLEVEL.

Ограничения при передаче данных в FINDSTR:

  • Все строки должны быть <= 8191 байт </li>
  • Последняя строка должна не быть одним символом без перевода строки

Пуленепробиваемое решение JREPL.BAT

Если у вас есть моя JREPL утилита , то есть «простой» один вкладыш, который должен работать всегда (я использовал продолжение строки, чтобы его было легче читать):

findstr /m /i "foo" "%WINDIR%\system32\drivers\etc\hosts" >nul ||^
jrepl "^" "" /jend "output.WriteLine('8.8.8.8 foo')"^
      /f "%WINDIR%\system32\drivers\etc\hosts" /o -

Он просто читает каждую строку и записывает ее снова с разделителями строк \ r \ n, а затем параметр /JEND добавляет дополнительныестрока в конце.

0 голосов
/ 28 декабря 2018

Более простой способ:

@echo off

find /C /I "foo" %windir%\system32\drivers\etc\hosts
if %errorlevel% NEQ 0 (echo. & echo 8.8.8.8 foo)>>%WINDIR%\System32\drivers\etc\hosts

, который для вас однострочный и более простой.

0 голосов
/ 28 декабря 2018

Я предлагаю следующий код пакетного файла для этой задачи:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "HostsFile=%SystemRoot%\System32\drivers\etc\hosts"
if not "%ProgramFiles(x86)%" == "" if exist %SystemRoot%\Sysnative\cmd.exe set "HostsFile=%SystemRoot%\Sysnative\drivers\etc\hosts"
if not exist %HostsFile% goto AppendData
%SystemRoot%\System32\findstr.exe /I /L /C:"foo" %HostsFile% >nul
if not errorlevel 1 goto EndBatch
%SystemRoot%\System32\findstr.exe /R /V "$" %HostsFile% >nul
if not errorlevel 1 echo/>>%HostsFile%
:AppendData
>>%HostsFile% echo 8.8.8.8  foo
:EndBatch
endlocal

Третья строка определяет переменную среды HostsFile со стандартным путем к файлу, который находится прямо в пакетном файле, выполняемом в 32-битной Windows с помощью32-разрядная cmd.exe или в 64-разрядной Windows с 64-разрядной cmd.exe в каталоге %SystemRoot%\System32.

В четвертой строке учитывается перенаправитель файловой системы Windows в соответствии с Детали реализации WOW64 .Пакетный файл выполняется в 64-битной Windows, если определена переменная среды с именем ProgramFiles(x86) с непустым значением.Но пакетный файл выполняется 32-битным cmd.exe в каталоге %SystemRoot%\SysWOW64, если есть %SystemRoot%\Sysnative\cmd.exe.Перенаправитель Sysnative не существует для приложений x64.В этом случае на файл hosts необходимо ссылаться из 32-битной среды в 64-битной Windows с использованием перенаправителя Sysnative в пути к файлу.

Далее проверяется, существует ли файл hosts ввсе.Если файл не существует, добавляемая строка данных может быть напрямую записана в файл без каких-либо дополнительных проверок, в результате чего в этом случае создается файл hosts.

В противном случае команда FINDSTR используется для поиска без учета регистра с буквально интерпретированной строкой поиска для foo с перенаправлением, возможно, найденных строк на устройство NUL . FINDSTR завершается со значением 0, если есть хотя бы одно положительное совпадение, и со значением 1, если искомая строка не может быть найдена ни в одной строке.

if not errorlevel 1 означает ЕСЛИ код выхода НЕ БОЛЬШЕ ИЛИ РАВНО 1 , или другими словами НИЖЕ, ЧЕМ 1 , или в этом случае РАВНО 0 из-за FINDSTR никогда не завершается с отрицательным значением, как почти все приложения и команды.Таким образом, если это условие истинно, файл hosts содержит хотя бы один раз искомую строку и ничего не нужно изменять в файле.

В противном случае FINDSTR используется еще раз для поиска в этот раз срегулярное выражение для конца строки и для вывода всех строк не , имеющих конец строки из-за опции /V.Таким образом, если последняя строка в файле hosts не имеет конца строки, FINDSTR завершается со значением 0 из-за того, что у нее есть одна строка без конца строки, в результате чего этот вывод перенаправляется на устройство NUL .

Окончание строки добавляется к файлу hosts, если FINDSTR завершено со значением 0 из-за того, что файл hosts заканчивается без окончания строки перед добавлением следующей строки данных кДобавить к этому файлу.

Приведенный выше код не работает, если командный файл не выполняется с повышенными разрешениями локального администратора или файл hosts имеет атрибут только для чтения или защищен от измененияскрипт.

Чтобы понять используемые команды и то, как они работают, откройте окно командной строки, выполните там следующие команды и полностью прочитайте все страницы справки, отображаемые для каждой команды.

  • echo /?
  • endlocal /?
  • findstr /?
  • goto /?
  • if /?
  • set /?
  • setlocal /?

См. Также тему форума DosTips: ECHO.Не в состоянии дать текст или пустую строку - вместо этого используйте ECHO /

0 голосов
/ 28 декабря 2018

Если вы не возражаете против новой строки / пустой строки, вы можете добавить

ECHO. >>%WINDIR%\System32\drivers\etc\hosts

т.е.

@echo off

FIND /C /I "foo" %WINDIR%\system32\drivers\etc\hosts
IF %ERRORLEVEL% NEQ 0 (
    ECHO.>>%WINDIR%\System32\drivers\etc\hosts
    ECHO 8.8.8.8 foo>>%WINDIR%\System32\drivers\etc\hosts

)
...