【问题标题】:Why does ECHO command print some extra trailing space into the file?为什么 ECHO 命令会在文件中打印一些额外的尾随空格?
【发布时间】:2017-10-27 06:02:44
【问题描述】:

我正在从一个数据文件中读取多行并将其附加到另一个文件中。问题是附加行末尾的输出文件中有一些额外的空间。必须根据我的要求修剪尾随空格,因为在原始数据文件中,行尾没有空格。我尝试了所有可能的事情,但我仍然无法做到这一点。

@echo off
setlocal enabledelayedexpansion
FOR /F "delims=" %%c IN (C:\Users\184863\Desktop\mydata.txt) DO ( 
echo %%c>>temp_data.txt 
)
endlocal

我尝试过的选项:

  1. echo %%c>>temp_data.txt ... 得到 1 个空格的行尾

  2. set lines=%%c
    echo !lines!>>temp_data.txt ... 得到 1 个空格的行尾

  3. echo !lines:~0,-1!>>temp_data.txt ... 修剪的行的最后一个字符

  4. set lines=!lines: =!
    echo !lines!>>temp_data.txt ... 行内的所有空格也被修剪(只需要修剪行尾,原始数据文件中不存在)

【问题讨论】:

    标签: windows batch-file


    【解决方案1】:

    您在echo %%c>>temp_data.txt(以及其他)行上有一个终端空间,应该删除它。这是终端空格引起的混乱的典型特征。

    【讨论】:

    • @Magoo..i 删除了末尾的空格。但是我的文件 mydata.txt 中有一个小问题,例如“[code=119888#!198; ttps://egrul.nalog. ru/]”在我复制到 temp_data.txt 之后它看起来像“[code=119888#//egrul.nalog.ru/]”。在“!198;https:”之间删除了字符。我观察到(!和:)之间的字符没有打印。这个问题的任何线索。
    • !varname!delayed expansion 被调用时指的是varname 的当前值,就像%varname% 指的是@987654327 中varname 的解析时间值@。该代码将! 之后的字符串作为子字符串替换结构(如!varname:string1=string2!)进行交互。删除enabledelayedexpansion,除非你真的需要它,
    【解决方案2】:

    echo 行的末尾有一个尾随空格,正如Magoo 已经写的那样,ECHO 不会忽略它。这个尾随空格也是由 ECHO%%c 之后输出的。

    重定向通常写在命令行的末尾,但它可以写在任何地方。也可以在开头编写重定向,如下所示或在中间某处,如在this answer 中的FOR 命令行中可以看到的那样。 ECHO 命令行的解析与所有其他命令行不同,因为双引号字符串之外的空格字符不会被解释为参数分隔符,因此 ECHO中的每个空格字符> 命令行很重要,由 ECHO 输出,包括> 等重定向运算符之前的命令行。

    这很容易被看到

    • 创建一个只包含echo Test>Test.txt  的批处理文件,Test.txt 后面有一个空格,
    • 打开命令提示符窗口,然后
    • 在命令提示符窗口中运行此批处理文件。

    输出为echo Test  1>Test.txt。所以> 被Windows 命令解释器替换为 1>(空格,一,右尖括号),并另外移动到行尾。 ECHO 命令行上的这种移动会导致最初的尾随空格在文本 Test 之后向左移动,因此也由 ECHO 输出。

    在整个命令块预处理期间的命令行修改也可以通过在命令提示符窗口中运行不带@echo off 的原始发布的批处理代码来调试批处理文件。 Windows 命令解释器输出 mydata.txt 包含单行 [code=119888#!198; ttps://egrul.nalog.ru/]:

    setlocal enabledelayedexpansion
    FOR /F "delims=" %c IN (C:\Users\184863\Desktop\mydata.txt) DO (echo %c  1>>temp_data.txt )
    (echo [code=119888#!198; ttps://egrul.nalog.ru/]  1>>temp_data.txt )
    endlocal
    

    >>temp_data.txt 之后的尾随空格现在是在预处理整个 FOR 命令行之后,该命令块只包含一个命令,留给 1>>temp_data.txt。当 FOR 执行 ECHO 命令行时,尾随空格现在是从 mydata.txt 1>>temp_data.txt 读取的行之间的附加空格,ECHO。

    应始终考虑在预处理/解析命令行后由 Windows 命令解释器实际执行的内容,而不是批处理文件中写入的内容。

    启用了进一步延迟的环境变量扩展,这会导致在执行 ECHO 命令之前,Windows 命令解释器会为 !VariableName! 处理从 %%c 引用的文件中读取的行。行中两个感叹号之间的所有内容都被解释为变量名,因此如果没有这样的环境变量,则分别替换为引用变量的值。在执行 ECHO 之前,在对行进行额外处理期间,Windows 命令解释器会简单地删除一个(剩余的)感叹号。

    解决方案 1:

    @echo off
    setlocal EnableExtensions DisableDelayedExpansion
    for /F "usebackq delims=" %%I in ("%USERPROFILE%\Desktop\mydata.txt") do >>temp_data.txt echo(%%I
    endlocal
    

    在此批处理代码中明确禁用延迟的环境变量扩展,以将感叹号始终解释为文字字符。

    在命令echo和循环变量引用%%I之间使用(代替空格字符来输出以/?开头的行正确而不是命令的使用帮助ECHO 就像使用 echo %%I 和从文本文件 mydata.txt 读取的行在 0 个或多个前导空格/制表符之后以 /? 开头一样。

    带有要读取的行的文本文件是使用预定义的Windows environment variableUSERPROFILE 括在双引号中指定的,以便在任何Windows 计算机上工作。双引号需要选项 usebackq 来获取文件名字符串,路径被解释为要从中读取行的文本文件名。

    由于一行可能以 0 到 9 范围内的数字结尾,所以不好使用:

    echo %%c>>temp_data.txt
    

    最好在 ECHO 命令行的开头指定重定向运算符,然后在后面指定echo %%c,不带空格。请阅读有关 Using command redirection operator 的 Microsoft 文档以了解更多信息。

    请注意,FOR 会忽略空行以及所有以分号开头并带有所用选项的行。 ; 是选项 eol(行尾)的默认值,此批处理文件中未明确指定。

    在将@echo off 修改为@echo ON 从命令提示符窗口中运行这个小批处理文件而不是双击它时,可以看到Windows 命令解释器真正执行的是什么:

    for /F "usebackq delims=" %I in ("C:\Users\184863\Desktop\mydata.txt") do echo %I 1>>temp_data.txt
    echo [code=119888#!198; ttps://egrul.nalog.ru/] 1>>temp_data.txt
    

    所以在执行前对批处理文件的每个命令行进行预处理后,可以看出Windows命令解释器最终执行的是哪个命令行。 >> 1>> 替换(注意开头插入空格),开头的重定向被移到 ECHO 命令行的末尾。

    另一种解决方案是将命令 ECHO 括在圆括号中以形成命令块,并仅使用命令 ECHO 将该命令块的输出重定向到文件,即使用(echo %%c) >>temp_data.txt) 之后的空格数不再重要。因此,(echo %%c)>> temp_data.txt 在重定向运算符 >> 之后带有一个空格,并且在行尾有一个尾随空格,导致文件 temp_data.txt 中的文本与使用 >>temp_data.txt echo %%c 时相同。

    解决方案 2:

    @echo off
    copy /B temp_data.txt+"%USERPROFILE%\Desktop\mydata.txt" temp_data.txt >nul
    

    COPY 命令可用于将使用+ 运算符指定的多个文件的内容合并到最后指定的单个文件中。此处使用此功能将来自用户桌面上mydata.txt 的行附加到现有的temp_data.txt。需要选项 /B(二进制数据)以避免 COPY 附加到输出文件 temp_data.txt ^Z,它是具有十六进制代码值 1A 的替换控制字符 SUB

    这个解决方案肯定比第一个更好,因为文件mydata.txt 包含什么并不重要。

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

    • copy /?
    • echo /?
    • endlocal /?
    • for /?
    • setlocal /?

    【讨论】:

      【解决方案3】:

      这应该是必要的,包括需要注释第 100 行。

      一:非必要时不要使用延迟扩展。
      二:删除 echo 命令中的尾随空格。

      @(
          SETLOCAL
          ECHO OFF
          SET "_File=C:\Users\184863\Desktop\mydata.txt"
          SET "_Count="
          SET "_Comment=Your Special Comment "
      )
      
      FOR /F "tokens=* delims=" %%c IN (%_File%) DO (
          SET /A "Count+=1">NUL
          CALL ECHO.[%COUNT%] | FIND "[100]">NUL && (
              ECHO:%_Comment%%~c
          ) || (
              ECHO.%%c
          )
      )>>"%~dp0temp_data.txt"
      
      REM Replace the original file with the commented File
      MOVE /Y "%~dp0temp_data.txt" "%_File%"
      
      (
          ENDLOCAL
          EXIT /B 0
      )
      

      【讨论】:

      • 我认为出于我的要求,我必须使用延迟扩展,因为我需要使用 for 循环中的计数器计算每一行,如果行号为 100,我需要添加特定的注释。可以你有什么想法可以满足我的要求。
      • @Munu,不小心向错误的用户发送了消息,我修改了解决方案以满足您的需求,并决定将其拆分为一个单独的子目录以减少混淆。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-01-01
      • 2020-04-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多