是否有用于转换文件行尾的 Windows 命令?
我们有一个 test.bat
,我们需要运行它来启动我们的服务器。我们使用 Perforce,我们需要在我们的工作空间中有 unix 行尾。出于某种原因,我们不允许在工作区中将行尾更改为 Windows。但是,服务器在 Windows 上运行。
每次我必须运行 bat 文件时,我都会在 Notepad++ 中打开它,然后选择编辑→EOL 转换→Windows。有没有办法自动化这个,这样我们每次与 Perforce 同步时就不需要手动更改行尾?
提前致谢。
这实际上可以使用 Windows NT 及更高版本中包含的 more
命令非常容易地完成。要将包含 UNIX EOL(行尾)\n
的 input_filename
转换为包含 Windows EOL \r\n
的 output_filename
,只需执行以下操作:
TYPE input_filename | MORE /P > output_filename
more
命令具有您可能不知道的其他格式选项。运行 more/?
以了解 more
还能做什么。
我正在处理 CRLF
问题,因此我决定构建非常简单的转换工具(在 NodeJS 中):
所以如果你有安装了 npm 的 NodeJS,你可以试试:
npm i -g eol-converter-cli
eolConverter crlf "**/*.{txt,js,java,etc}"
可以使用 Glob 正则表达式(与 shell 中的正则表达式相同)动态配置路径。
因此,如果您可以使用 NodeJS,这真的很简单,您可以集成此命令将整个工作区转换为所需的行尾。
您可以在 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) 连接起来将其写入文件。
Get-Content
周围的括号使这成为可能)。至于一般的“就地”编辑:see here。
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
以 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
尝试这个:
(for /f "delims=" %i in (file.unix) do @echo %i)>file.dos
会话协议:
C:\TEST>xxd -g1 file.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 file.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..
我对此的贡献,转换文件夹中的多个文件:for %%z in (*.txt) do (for /f "delims=" %%i in (%%z) do @echo %%i)>%%z.tmp
如果你有 bash(例如 git bash),你可以使用以下脚本从 unix2dos 转换:
ex filename.ext <<EOF
:set fileformat=dos
:wq
EOF
同样,从 dos2unix 转换:
ex filename.ext <<EOF
:set fileformat=unix
:wq
EOF
您可以创建一个简单的批处理脚本来为您执行此操作:
TYPE %1 | MORE /P >%1.1
MOVE %1.1 %1
然后运行 <batch script name> <FILE>
和 <FILE>
将立即转换为 DOS 行尾。
我使用 windows
上的 git bash
克隆了我的 git 项目。然后所有文件都有 LF
结尾。我们的存储库默认有 CRLF
结尾。
我删除了该项目,然后使用 Windows Command Prompt
再次克隆它。 CRLF
结尾是完整的。就我而言,如果我改变了项目的结局,那么它会导致巨大的提交,并会给我的队友带来麻烦。所以,就这样做了。希望这可以帮助某人。
这是一个简单的 unix2dos.bat 文件,它保留了空行和感叹号:
@echo off
setlocal DisableDelayedExpansion
for /f "tokens=1,* delims=:" %%k in ('findstr /n "^" %1') do echo.%%l
输出到标准输出,因此如果需要,将 unix2dos.bat 输出重定向到文件。
它通过以下方式避免了其他先前提出的 for /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
的冒号作为echo 命令后的标记分隔符。
我会留给 Jeb 来解释是否存在 echo:something
可能失败的极端情况 :-)
我只能说最后一个版本成功地恢复了我巨大的 batch library 上的行尾,所以例外,如果任何,一定非常罕见!
:
。这会破坏所有批处理功能。顺便提一句。测试以转换具有类似 \..\..\windows\system32\calc.exe
的行的文件。要解决此问题,请查看 this explanation
..\..\..\..\..\windows\system32\calc.exe
试试。唯一的安全 ECHO 形式是echo(
。一个班轮是可能的,但我想这很棘手
根据 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
聚会迟到了,但仍然没有使用 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
在每行前加上 <line number>:
,这样可以避免跳过空行或以 ;
开头的行。
要删除 <number>:
,不能使用 FOR "tokens=1,* delims=:"
选项,因为这也会删除一行中的所有前导冒号。
因此,行号被 set "line=!line:*:=!"
删除,这需要 EnableDelayedExpansion。
但是对于 EnableDelayedExpansion
,行 set "line=%%L"
将删除所有感叹号和插入符号(仅当感叹号在行中时)。
这就是为什么我之前禁用延迟扩展并仅在需要的两条线中启用它。
(echo(!line!)
看起来很奇怪,但有一个优点,即 echo(
可以显示 !line!
中的任何内容,并且外括号避免了行尾的意外空格。
要将 UNIX(LF) 转换为 Windows(CR-LF),请在 Windows 终端上使用下一个命令。
type file.txt > new_file.txt
我正在参加 AWS 课程,并且经常不得不从 AWS Web 表单中的文本框复制到 Windows 记事本。所以我只在我的剪贴板上得到了 LF 分隔的文本。我偶然发现将它粘贴到我的 Delphi 编辑器中,然后按 Ctrl+K+W 会将文本写入带有 CR+LF 分隔符的文件。 (我敢打赌许多其他 IDE 编辑器也会这样做)。
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)>"%~2"
之类的东西就可以了。
set TargetFile=%2 rem c:\test\out.txt
也需要改进。而且,顺便说一句,你的 "tokens=*"
也是。
more /P <input_file >output_file