回声文件换行符末尾

时间:2018-12-28 10:11:25

标签: windows batch-file command-line

这是我的将数据添加到特定文件的脚本:

@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

当文件末尾包含换行符时,它可以正常工作:

来自:

data
 

收件人:

data
8.8.8.8 foo

但是当文件末尾不包含新行时,我将获得连接的行:

来自:

data

收件人:

data8.8.8.8 foo

对于带有 AND 且结尾没有换行符的文件,我该怎么做才能使代码正常工作?

4 个答案:

答案 0 :(得分:2)

对于此任务,我建议使用以下批处理文件代码:

@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 File System Redirector考虑​​了WOW64 Implementation Details。如果定义了名称为ProgramFiles(x86)且具有非空值的环境变量,则该批处理文件将在64位Windows上执行。但是,如果存在cmd.exe,则批处理文件由目录%SystemRoot%\SysWOW64中的32位%SystemRoot%\Sysnative\cmd.exe执行。重定向器Sysnative对于x64应用程序不存在。在这种情况下,必须在文件路径中使用hosts重定向器,才能从64位Windows的32位环境中引用文件Sysnative

接下来检查文件hosts是否存在。如果该文件不存在,则可以在不进行任何进一步检查的情况下将要追加的数据行直接写入该文件,从而可以在这种情况下创建文件hosts

否则,命令 FINDSTR 用于搜索不区分大小写的foo字面意义的搜索字符串,并将可能找到的行重定向到设备 NUL 。如果存在至少一个正匹配项,则 FINDSTR 以值0退出,如果在任何行上都找不到搜索字符串,则以值1退出。

if not errorlevel 1表示 IF 退出代码为 NOT GREATER或EQUAL 1 ,即低于1 ,或在这种情况下,由于 FINDSTR 而导致等于0 的情况下,几乎所有应用程序和命令都不会以负值退出。因此,如果此条件为真,则文件hosts至少包含一次搜索到的字符串,并且文件上没有任何更改。

否则,再次使用 FINDSTR 来搜索带有正则表达式的行尾,并输出所有由于选项{{ 1}}。因此,如果文件/V中的最后一行没有行尾,则 FINDSTR 以值hosts退出,因为输出了一行无行尾,因此该输出重定向到设备< strong> NUL

如果由于文件0而退出 FINDSTR 并返回值hosts,则行结尾将附加到文件0,而在附加下一个数据之前,行末没有结尾添加到此文件的行。

如果未在本地管理员提升权限的情况下执行批处理文件,或者文件hosts设置了只读属性,或者受脚本保护,则该代码无法正常工作。

要了解所使用的命令及其工作方式,请打开命令提示符窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。

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

另请参阅DosTips论坛主题:ECHO. FAILS to give text or blank line - Instead use ECHO/

答案 1 :(得分:2)

FINDSTR有一个奇怪的怪癖,如果输入流不以\r\n(换行)结尾,它会将\n(回车,换行)附加到管道输入。有关更多信息,请参见https://stackoverflow.com/a/8844873/1012053上的 管道和重定向输入可能附加了<CR><LF> 部分。

仅当需要时,您可以使用此技巧有选择地添加缺少的换行符。

@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语句来检查{{1 }}。

管道输入FINDSTR的限制:

  • 行必须全部为<= 8191字节长
  • 最后一行必须 not 不包含换行符的单个字符

防弹JREPL.BAT解决方案

如果您有我的JREPL utility,则可以使用一种“简单”的衬纸,该衬纸应始终有效(我使用了连续行以使其更易于阅读):

ERRORLEVEL

它只是读取每一行,并使用\ r \ n行终止符再次将其写出,然后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 - 选项在末尾追加多余的行。

答案 2 :(得分:1)

一种更简单的方法是:

@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

这是单行代码,对您来说更简单。

答案 3 :(得分:0)

如果您不介意其他换行/空白行,则可以添加

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

)