【问题标题】:Windows command to convert Unix line endings?Windows命令转换Unix行尾?
【发布时间】:2013-07-08 21:48:48
【问题描述】:

是否有用于转换文件行尾的 Windows 命令?

我们有一个test.bat,我们需要运行它来启动我们的服务器。我们使用 Perforce,我们需要在工作空间中有 unix 行尾。出于某种原因,我们不允许在工作区中将行尾更改为 Windows。但是,服务器在 Windows 上运行。

每次我必须运行 bat 文件时,我都会在 Notepad++ 中打开它,然后选择编辑→EOL 转换→Windows。有没有办法自动化这个,这样我们就不需要在每次与 Perforce 同步时手动更改行尾?

提前致谢。

【问题讨论】:

    标签: windows unix batch-file cmd eol


    【解决方案1】:

    这实际上可以使用包含在 Windows NT 和更高版本中的more 命令非常容易地完成。要将包含 UNIX EOL(行尾)\ninput_filename 转换为包含 Windows EOL \r\noutput_filename,只需执行以下操作:

    TYPE input_filename | MORE /P > output_filename
    

    more 命令具有您可能不知道的其他格式选项。运行more/? 以了解more 还能做什么。

    【讨论】:

    • 这似乎为不以换行符结尾的文件添加了一个额外的换行符,如果这对您的特定场景很重要,请注意。
    • 不幸的是,这也将所有选项卡都弄乱了。
    • 我需要相反的。有什么想法吗?
    • 很好的答案!稍微简单一点:more /P <input_file >output_file
    • @Sebastian Windows 9 是什么?
    【解决方案2】:

    使用unix2dos 实用程序。您可以下载二进制文件here

    【讨论】:

    • 再次,它只是记事本++的替代品。不会真正让这个自动化。我将不得不运行这个工具。到目前为止,我确实更改了 notepad++ 中的行尾。
    • 它是一个命令行工具。它更适合自动化,然后是 GUI 工具。您可以编写一个定期的at 作业,它会过滤您放置批处理文件的某个文件夹中的所有文件。这完全取决于您所说的自动化是什么意思。
    【解决方案3】:

    我正在处理 CRLF 问题,所以我决定构建非常简单的转换工具(在 NodeJS 中):

    我是NodeJS EOL converter CLI

    所以如果你安装了 NodeJS 和 npm,你可以试试:

    npm i -g eol-converter-cli
    eolConverter crlf "**/*.{txt,js,java,etc}"
    

    可以使用 Glob 正则表达式(与 shell 中的正则表达式相同)动态配置路径。

    因此,如果您可以使用 NodeJS,那真的很简单,您可以集成此命令将整个工作区转换为所需的行尾。

    【讨论】:

    【解决方案4】:

    您无需使用 VBScript 中的其他工具即可做到这一点:

    Do Until WScript.StdIn.AtEndOfStream
      WScript.StdOut.WriteLine WScript.StdIn.ReadLine
    Loop
    

    将以上几行放入一个文件unix2dos.vbs 并像这样运行它:

    cscript //NoLogo unix2dos.vbs <C:\path\to\input.txt >C:\path\to\output.txt
    

    或者像这样:

    type C:\path\to\input.txt | cscript //NoLogo unix2dos.vbs >C:\path\to\output.txt
    

    您也可以在 PowerShell 中执行此操作:

    (Get-Content "C:\path\to\input.txt") -replace "`n", "`r`n" |
      Set-Content "C:\path\to\output.txt"
    

    可以进一步简化为:

    (Get-Content "C:\path\to\input.txt") | Set-Content "C:\path\to\output.txt"
    

    上述语句无需显式替换即可工作,因为Get-Content 在任何类型的换行符(CR、LF 和 CR-LF)处隐式拆分输入文件,而Set-Content 将输入数组与 Windows 换行符(CR- LF) 在将其写入文件之前。

    【讨论】:

    • @FranklinYu 使用 PowerShell 方法,您可以将修改后的内容写回同一个文件(Get-Content 周围的括号使这成为可能)。至于一般的“就地”编辑:see here.
    • 对于第一个带有 -replace 的 powershell 方法,您必须将 -raw 选项添加到 get-content 以执行您想要的操作。只是不要在同一个文件上做两次。您甚至不需要引用文件名。请注意,在 powershell 5 中使用“>”或“out-file”会产生“unicode”编码文件与“ansi”。
    【解决方案5】:

    Windows 的 MORE 不可靠,它不可避免地会破坏 TAB 并添加行。

    unix2dos 也是 MinGW/MSYS、Cygutils、GnuWin32 和其他 unix 二进制端口集合的一部分 - 并且可能已经安装。

    python 存在时,这一行将任何行尾转换为当前平台 - 在任何平台上:

    TYPE UNIXFILE.EXT | python -c "import sys; sys.stdout.write(sys.stdin.read())" > MYPLATFILE.EXT
    

    python -c "import sys; sys.stdout.write(open(sys.argv[1]).read())" UNIXFILE.EXT > MYPLATFILE.EXT
    

    或根据您的平台将单行代码放入 .bat / shell 脚本并放在 PATH 上:

    @REM This is any2here.bat
    python -c "import sys; sys.stdout.write(open(sys.argv[1]).read())" %1
    

    并像使用该工具

    any2here UNIXFILE.EXT > MYPLATFILE.EXT
    

    【讨论】:

      【解决方案6】:

      以 TampaHaze 和 MD XF 的有用答案为基础。

      这会将当前目录中的所有 .txt 文件就地从命令提示符中的 LF 更改为 CRLF

      for /f "delims=" %f in ('dir /b "*.txt"') do ( type "%f" | more /p > "%f.1" & move "%f.1" "%f" )
      

      如果您不想验证每一个更改

      移动

      移动/y

      要包含子目录的变化

      目录 /b

      目录 /b /s

      要在包含子目录的批处理文件中执行所有这些操作,而不提示.txt 文件,请使用下面

      @echo off
      setlocal enabledelayedexpansion
      
      for /f "delims=" %%f in ('dir /s /b "*.txt"') do (
          type "%%f" | more /p > "%%f.1"
          move /y "%%f.1" "%%f" > nul
          @echo Changing LF-^>CRLF in File %%f
      )
      echo.
      pause
      

      【讨论】:

      • 不,如果文件路径中有空格,例如“C:\Program Files\FileMaker\FileMaker Server\HTTPServer\conf\”,这将完全失败。
      【解决方案7】:

      试试这个:

      (for /f "delims=" %i in (file.unix) do @echo %i)>file.dos
      

      会话协议:

      C:\TEST>xxd -g1 文件.unix 0000000: 36 31 36 38 39 36 32 39 33 30 38 31 30 38 36 35 6168962930810865 0000010: 0a 34 38 36 38 39 37 34 36 33 32 36 31 38 31 39 .486897463261819 0000020: 37 0a 37 32 30 30 31 33 37 33 39 31 39 32 38 35 7.72001373919285 0000030: 34 37 0a 35 30 32 32 38 31 35 37 33 32 30 32 30 47.5022815732020 0000040:35 32 34 0a 524。 C:\TEST>(for /f "delims=" %i in (file.unix) do @echo %i)>file.dos C:\TEST>xxd -g1 文件.dos 0000000: 36 31 36 38 39 36 32 39 33 30 38 31 30 38 36 35 6168962930810865 0000010: 0d 0a 34 38 36 38 39 37 34 36 33 32 36 31 38 31 ..48689746326181 0000020: 39 37 0d 0a 37 32 30 30 31 33 37 33 39 31 39 32 97..720013739192 0000030:38 35 34 37 0d 0a 35 30 32 32 38 31 35 37 33 32 8547..5022815732 0000040: 30 32 30 35 32 34 0d 0a 020524..

      【讨论】:

      • 它有效,但它似乎也从文件中删除了所有空行。 :(
      • @MarioVilas 是的,你是对的。您可以为此使用flip
      【解决方案8】:

      我对此的贡献,转换文件夹中的几个文件: for %%z in (*.txt) do (for /f "delims=" %%i in (%%z) do @echo %%i)&gt;%%z.tmp

      【讨论】:

        【解决方案9】:

        如果你有 bash(例如 git bash),你可以使用以下脚本从 unix2dos 转换:

        ex filename.ext <<EOF
        :set fileformat=dos
        :wq
        EOF
        

        类似地,从 dos2unix 转换:

        ex filename.ext <<EOF
        :set fileformat=unix
        :wq
        EOF
        

        【讨论】:

          【解决方案10】:

          您可以创建一个简单的批处理脚本来为您执行此操作:

          TYPE %1 | MORE /P >%1.1
          MOVE %1.1 %1
          

          然后运行&lt;batch script name&gt; &lt;FILE&gt;&lt;FILE&gt; 将立即转换为DOS 行尾。

          【讨论】:

            【解决方案11】:

            我在windows 上使用git bash 克隆了我的git 项目。然后所有文件都有LF 结尾。我们的存储库默认有CRLF 结尾。

            我删除了该项目,然后使用Windows Command Prompt 再次克隆它。 CRLF 的结尾是完整的。就我而言,如果我改变了项目的结局,那么它会导致巨大的提交,并且会给我的队友带来麻烦。所以,就这样做了。希望这可以帮助某人。

            【讨论】:

            • 有一种方法可以使用 git 将 CRLF 转换为 LF 我只是用你的方法来获得 LF 结尾,但我无法让它工作。所以我决定改变 git configs 这里是一个 sn-p: $ git config --global core.autocrlf input
            【解决方案12】:

            这是一个简单的 unix2dos.bat 文件,它保留了空白行和感叹号:

            @echo off
            setlocal DisableDelayedExpansion
            for /f "tokens=1,* delims=:" %%k in ('findstr /n "^" %1') do echo.%%l
            

            输出到标准输出,因此如果需要,请将 unix2dos.bat 输出重定向到文件。

            它通过以下方式避免了之前为 /f 批处理循环解决方案提出的其他陷阱:
            1)关闭延迟扩展,避免吃掉感叹号。
            2) 使用 for /f 标记器本身从findstr /n 输出行中删除行号。
            (使用 findstr /n 也需要获取空行:如果 for /f 直接从输入文件中读取,它们将被删除。)

            但是,正如 Jeb 在下面的评论中指出的那样,上述解决方案有一个其他解决方案没有的缺点:它在行首省略了冒号。

            所以 2020-04-06 更新只是为了好玩,这是另一个基于 findstr.exe 的 1-liner,它似乎工作正常,没有上述缺点:

            @echo off
            setlocal DisableDelayedExpansion
            for /f "tokens=* delims=0123456789" %%l in ('findstr /n "^" %1') do echo%%l
            

            额外的技巧是:
            3) 使用数字 0-9 作为分隔符,以便tokens=* 跳过初始行号。
            4) 使用冒号,在行号后插入findstr /n,作为回显命令后的标记分隔符。

            我会让 Jeb 解释是否存在 echo:something 可能失败的极端情况 :-)
            我只能说最后一个版本成功恢复了我巨大的batch library 上的行尾,所以如果有例外,一定非常罕见!

            【讨论】:

            • 这会从行首删除所有冒号:。这会破坏所有批处理功能。顺便提一句。测试转换带有\..\..\windows\system32\calc.exe 之类的行的文件。要解决这个问题,请查看this explanation
            • 你是对的!我想做一个 1-liner,比以前发布的解决方案更简单更好,但显然这无法做到。到目前为止,你的是唯一正确的。
            • 但是挑战是不可抗拒的,也许我现在找到了另一个 1-line 解决方案,如上面编辑的文本所示:-)
            • 你又失败了 :-) 试试..\..\..\..\..\windows\system32\calc.exe。唯一的安全 ECHO 形式是echo(。一个班轮是可能的,但我想这很棘手
            • Caramba,schon wieder verpaßt!好吧,我暂时放弃。但我相信总有一天,我会成功的! :-)
            【解决方案13】:

            根据 Endoro 的回答,但要保留空白,试试这个:

            @echo off
            setlocal enabledelayedexpansion
            (for /f "tokens=* delims=:" %%i in ('findstr /n "^" file.unix') do (
                    set line=%%i
                    set line=!line:*:=!
                    echo(!line!
                    ))>file.dos
            

            【讨论】:

            • Ir Relevant 的解决方案工作正常,只是它去掉了所有感叹号 (!)。
            【解决方案14】:

            聚会迟到了,但仍然使用FOR /F 循环没有正确答案。
            (但你根本不需要 FOR 循环,solution from @TampaHaze 也可以工作,而且更简单)

            answer from @IR relevant 有一些缺点。
            它会去掉感叹号,也可以去掉插入符号。

            @echo off
            (
                setlocal Disabledelayedexpansion
                for /f "tokens=* delims=" %%L in ('findstr /n "^" "%~1"') do (
                    set "line=%%L"
                    setlocal enabledelayedexpansion
                    set "line=!line:*:=!"
                    (echo(!line!)
                    endlocal
                )
            ) > file.dos
            

            诀窍是使用findstr /n 为每一行加上&lt;line number&gt;: 前缀,这样可以避免跳过空行或以; 开头的行。
            要删除&lt;number&gt;:,不能使用FOR "tokens=1,* delims=:" 选项,因为这也会删除一行中的所有前导冒号。

            因此行号被set "line=!line:*:=!"删除,这需要EnableDelayedExpansion。
            但是对于EnableDelayedExpansionset "line=%%L" 行将删除所有感叹号和插入符号(仅当感叹号在行中时)。

            这就是为什么我之前禁用延迟扩展,只在需要的两行启用它。

            (echo(!line!) 看起来很奇怪,但有一个优点,echo( 可以显示!line! 中的任何内容,并且外括号避免了行尾的意外空格。

            【讨论】:

              【解决方案15】:

              要将 UNIX(LF) 转换为 Windows(CR-LF),请在 Windows 终端上使用下一个命令。

              type file.txt > new_file.txt
              

              【讨论】:

                【解决方案16】:

                我正在学习 AWS 课程,并且经常不得不从 AWS Web 表单中的文本框复制到 Windows 记事本。所以我只在我的剪贴板上得到了 LF 分隔的文本。我偶然发现将它粘贴到我的 Delphi 编辑器中,然后按 Ctrl+K+W 会将文本写入带有 CR+LF 分隔符的文件。 (我敢打赌许多其他 IDE 编辑器也会这样做)。

                【讨论】:

                  【解决方案17】:

                  Inserting Carriage Returns to a Text File

                  @echo off
                  set SourceFile=%1 rem c:\test\test.txt
                  set TargetFile=%2 rem c:\test\out.txt
                  
                  if exist "%TargetFile%" del "%TargetFile%"
                  for /F "delims=" %%a in ('type "%SourceFile%"') do call :Sub %%a
                  rem notepad "%TargetFile%"
                  goto :eof
                  
                  
                  :Sub
                  echo %1 >> "%TargetFile%"
                  if "%2"=="" goto :eof
                  shift
                  goto sub
                  

                  【讨论】:

                  • 其实,他只要用(for /f "tokens=*" %%a in (%~1) do @echo.%%a)&gt;"%~2"之类的就行了。
                  • @AnsgarWiechers 是的,这个set TargetFile=%2 rem c:\test\out.txt 也需要改进。而且,顺便说一句,你的"tokens=*" 也是。
                  • @Endoro REM 是批处理文件中的注释,你可以取出 %1 rem 然后给它你需要的特定文件。当我提供链接时,我觉得我不需要进一步记录,因为您已经在使用批处理文件,对吗?请对其进行测试,因为它确实有效,并且可以随意集成到您现有的批处理文件中。谢谢!
                  • 在 Windows 7 中工作正常。我在 Notepad++ 中使用 Unix 的 EOL 创建了一个文件 c:\test\test.txt。之后,我只是运行了批处理文件。同样,这不是我的代码,是我稍微修改后不显示记事本的代码?我可以向 OP 展示如何使其工作,而不是最后的评论。