kno*_*t22 10 bash text-processing newlines
我有一个正在 Windows 计算机上处理的文本文件。bcp
在使用实用程序将数据从文件加载到数据库表之前,需要删除尾随制表符。
Bash 脚本中的以下命令删除了尾随选项卡:
sed 's/[\t]*$//' < ./input/raw.txt >> ./input/data.txt
Run Code Online (Sandbox Code Playgroud)
CR
但它将-转换LF
为LF
导致bcp
命令失败的原因。
为了努力保持CR
-LF
我尝试了这个:
sed 's/[\t]*$/$CR/' < ./input/raw.txt >> ./input/data.txt
Run Code Online (Sandbox Code Playgroud)
但这导致:
期望的结果是:
如何修改命令以获得所需的输出?
Jim*_* L. 25
您需要安装该unix2dos
软件包。它有两个实用程序:
unix2dos Convert UNIX newlines to CR-LF
dos2unix Convert DOS CR-LF to UNIX newlines
Run Code Online (Sandbox Code Playgroud)
让我们创建一个包含五行的测试文件,并执行十六进制转储来检查行结尾:
$ jot -w 'line %d' 5 > foo
$ hexdump -C foo
00000000 6c 69 6e 65 20 31 0a 6c 69 6e 65 20 32 0a 6c 69 |line 1.line 2.li|
00000010 6e 65 20 33 0a 6c 69 6e 65 20 34 0a 6c 69 6e 65 |ne 3.line 4.line|
00000020 20 35 0a | 5.|
00000023
Run Code Online (Sandbox Code Playgroud)
我们看到每一行都以换行符(十六进制 0a)结尾。
现在我们将这些换行符转换为 DOS CR-LF 行结尾,并再次检查:
$ unix2dos foo
$ hexdump -C foo
00000000 6c 69 6e 65 20 31 0d 0a 6c 69 6e 65 20 32 0d 0a |line 1..line 2..|
00000010 6c 69 6e 65 20 33 0d 0a 6c 69 6e 65 20 34 0d 0a |line 3..line 4..|
00000020 6c 69 6e 65 20 35 0d 0a |line 5..|
00000028
Run Code Online (Sandbox Code Playgroud)
现在每行以 CR-LF 结束,十六进制 0d 0a。
最后,我们可以将文件转换回原始的 UNIX 换行符:
$ dos2unix foo
$ hexdump -C foo
00000000 6c 69 6e 65 20 31 0a 6c 69 6e 65 20 32 0a 6c 69 |line 1.line 2.li|
00000010 6e 65 20 33 0a 6c 69 6e 65 20 34 0a 6c 69 6e 65 |ne 3.line 4.line|
00000020 20 35 0a | 5.|
00000023
Run Code Online (Sandbox Code Playgroud)
Sté*_*las 15
请注意,在标准中sed
,删除行尾的sed 's/[\t]*$//'
所有反斜杠和字符。t
GNU 实现sed
仅在其环境中存在POSIXLY_CORRECT
变量时才执行此操作。
sed 's/\t*$//'
未指定,但至少对于 GNU 来说,无论是否在环境中,sed
都会删除尾随的 TAB 。POSIXLY_CORRECT
在这里你可以这样做:
sed $'s/\t*$/\r/'
Run Code Online (Sandbox Code Playgroud)
使用 ksh93 样式$'...'
的引号形式,其中类似\t
或 的内容\r
分别扩展为 TAB 和 CR。现在许多其他 shell 都支持这一点,并且将出现在 POSIX 标准的下一版本中sh
。
如果 shell 变量中有 TAB 和 CR 字符,则可以不使用这些字符,$'...'
例如:
eval "$(printf 'TAB="\t" CR="\r"')"
Run Code Online (Sandbox Code Playgroud)
你可以这样做:
sed "s/$TAB*\$/$CR/"
Run Code Online (Sandbox Code Playgroud)
但它必须在双引号内。在单引号内,不执行扩展。
现在,万一输入不以 LF 字符结尾(这将使其在 Unix 中成为无效文本),那些(sed
至少对于 GNU)将生成一个以 CR 字符结尾的文件,使其在 Unix 中无效。 DOS也是如此。
要将文本文件从 Unix 转换为 DOS,您可以使用该unix2dos
实用程序,这样就不会出现问题:
sed $'s/\t*$//' | unix2dos
Run Code Online (Sandbox Code Playgroud)
或者使用perl
的sed
模式:
perl -pe 's/\t*$//; s/\n/\r\n/'
Run Code Online (Sandbox Code Playgroud)
perl -p
其工作原理类似于sed
它为每行输入运行代码,只不过在perl
模式空间($_
那里)具有包含行分隔符的整行。它还支持那些\t
, \n
,\r
转义符(而标准sed
仅支持\n
且仅在正则表达式中),并且可以处理非文本文件。