【发布时间】:2014-03-05 15:23:28
【问题描述】:
在 OSX 上,我需要从我的 CSV 文件中删除行尾 CR (\r) 字符(在 cat -v 的输出中表示为 ^M):
$ cat -v myitems.csv
输出:
strPicture,strEmail^M
image1xl.jpg,me@example.com^M
我用 sed 和 perl 尝试了很多选项,但没有任何效果。
有什么想法吗?
【问题讨论】:
在 OSX 上,我需要从我的 CSV 文件中删除行尾 CR (\r) 字符(在 cat -v 的输出中表示为 ^M):
$ cat -v myitems.csv
输出:
strPicture,strEmail^M
image1xl.jpg,me@example.com^M
我用 sed 和 perl 尝试了很多选项,但没有任何效果。
有什么想法吗?
【问题讨论】:
库存实用程序解决方案:
注意:除非另有说明(sed -i 不兼容),以下解决方案适用于 OSX (macOS) 和 Linux。
如下使用sed,将\r\n替换为\n:
sed $'s/\r$//' myitems.csv
要更新输入文件就地,使用
sed -i '' $'s/\r$//' myitems.csv
-i '' 指定就地更新,'' 表示不应该对输入文件进行备份;如果您指定扩展名,例如 -i'.bak',原始输入文件将与该扩展名一起保存作为备份。
注意事项:
* 对于 GNU sed (Linux),要不创建备份文件,您必须只使用 -i,而不使用单独的 @987654335 @argument,这是在 OSX (macOS) 上使用的 GNU Sed 和 BSD Sed 之间的一个不幸的句法不兼容 - 请参阅我的 this answer 了解全文。
* -i 用临时名称创建一个新文件,然后替换原来的文件;最显着的后果是,如果原始文件是 符号链接,它会被替换为常规文件;详细讨论见this answer的下半部分。
注意:上面使用ANSI C-quoted string ($'...') 在sed 命令中创建\r 字符,因为BSD sed(在OS X 上使用的那个)本身不能识别这样的转义序列(请注意,Linux 发行版上使用的 GNU sed 会)。
Bash、Ksh 和 Zsh 支持 ANSI C 引用的字符串。
如果您不想依赖此类字符串,请使用:
sed 's/'"$(printf '\r')"'$//'
这里,\r 是通过 printf 创建的,并通过命令替换 ($(...)) 拼接到 sed 命令中。
使用perl:
perl -pe 's/\r\n/\n/' myitems.csv | cat -v
要更新输入文件就地,使用
perl -i -ple 's/\r\n/\n/' myitems.csv # -i'.bak' creates backup with suffix '.bak' first
关于就地更新的sed 的警告与上述相同。
使用awk:
awk '{ sub("\r$", ""); print }' myitems.csv # shorter: awk 'sub("\r$", "")+1'
BSD awk 不提供就地更新选项,因此您必须将输出捕获到不同的文件中;要使用临时文件并在之后替换原始文件,请使用以下成语:
awk '{ sub("\r$", ""); print }' myitems.csv > tmpfile && mv tmpfile myitems.csv
GNU awk v4.1 或更高版本提供 -i inplace 用于就地更新,与上述 sed 相同的警告适用。
以上所有变体的边缘情况:如果最后一个字符。在输入文件中恰好是一个单独的\r,没有跟随\n,它也将被替换为\n。
为了完整起见:这里是额外的,可能不是最佳的解决方案:
它们都不提供就地更新,但您可以使用上面介绍的> tmpfile && mv tmpfile myitems.csv 成语
使用tr:一个非常简单的解决方案,只需删除所有 \r 实例;因此,它只能在\r instance only 作为\r\n 序列的一部分出现时使用;然而,通常情况下是:
tr -d '\r' < myitems.csv
使用纯bash 代码:注意这会慢;就像tr 解决方案一样,这只能在\r 实例仅作为\r\n 序列的一部分出现时使用。
while IFS=$'\r' read -r line; do
printf '%s\n' "$line"
done < myitems.csv
$IFS 是内部字段分隔符,将其设置为\r 会导致read 将\r 之前的所有内容(如果存在)读取到变量$line 中(如果没有\r,则该行是按原样阅读)。 -r 阻止 read 解释输入中的 \ 实例。
极端情况:如果输入不以\n 结尾,最后一行将不会打印 - 你可以使用read -r line || [[ -n $line ]] 来解决这个问题。
【讨论】:
试试这个,它会解决你的问题。
dos2unix myitems.csv myitems.csv
【讨论】:
dos2unix 在 OSX 上默认不可用,但Homebrew 用户可以通过brew install dos2unix 获取。但是:dos2unix 默认会就地 转换文件,因此您可能只需要dos2unix myitems.csv(第二次指定文件只会尝试再次转换它)。相比之下,如果您想写入不同的输出文件,请使用dos2unix -n myitems.csv new-myitems.csv(适用于 OSX 和 Linux 版本)。
试试 unix2dos 命令。
例如:unix2dos infile outfile
http://en.wikipedia.org/wiki/Unix2dos
维基百科页面也有一些使用 perl 和 sed 的示例。
perl -i -p -e 's/\n/\r\n/' file
sed -i -e 's/$/\r/' file
【讨论】:
^M 的存在出现在 cat -v 的输出中以及OSX 参考建议它是关于删除 \r (CR) 字符。