从 CSV 中删除 \r (CR)

Sam*_*m T 3 csv macos newline sed

在 OSX 上,我需要从我的 CSV 文件中删除行尾 CR ( \r) 字符(表示为^M的输出cat -v):

$ cat -v myitems.csv
Run Code Online (Sandbox Code Playgroud)

输出:

strPicture,strEmail^M
image1xl.jpg,me@example.com^M
Run Code Online (Sandbox Code Playgroud)

我用 sed 和 perl 尝试了很多选项,但没有任何效果。

有任何想法吗?

mkl*_*nt0 5

具有库存实用程序的解决方案

注意:除非另有说明(sed -i不兼容),以下解决方案适用于 OSX (macOS) 和 Linux。

使用sed如下,替换\r\n\n

sed $'s/\r$//' myitems.csv
Run Code Online (Sandbox Code Playgroud)

就地更新输入文件,请使用

sed -i '' $'s/\r$//' myitems.csv
Run Code Online (Sandbox Code Playgroud)

-i ''指定就地更新,''表示不对输入文件进行备份;如果指定了扩展名,例如,-i'.bak'中,原始输入文件将保存与推广作为备份。
注意事项
*使用GNU sed(Linux)的,不创建一个备份文件,你必须使用-i,没有独立的''说法,这是GNU桑达和BSD桑达之间不幸的语法不兼容于OSX(Mac系统)使用-见是我对完整故事的回答
*-i创建一个具有临时名称的新文件,然后替换原始文件;最显着的后果是,如果原始文件是一个符号链接,它会被替换为一个普通文件;有关详细讨论,请参阅此答案的下半部分。

注意:上面使用ANSI C 引用的字符串( $'...')\rsed命令中创建字符,因为 BSD sed(在 OS X 上使用的那个)本身不能识别这样的转义序列(请注意,Linux 发行版上使用的GNU sed会)。
Bash、Ksh 和 Zsh 支持 ANSI C 引用的字符串。

如果您不想依赖此类字符串,请使用:

sed 's/'"$(printf '\r')"'$//'
Run Code Online (Sandbox Code Playgroud)

在这里,\r通过命令替换 ( )创建printf并拼接到sed命令中$(...)


使用perl

perl -pe 's/\r\n/\n/' myitems.csv | cat -v
Run Code Online (Sandbox Code Playgroud)

就地更新输入文件,请使用

perl -i -ple 's/\r\n/\n/' myitems.csv  # -i'.bak' creates backup with suffix '.bak' first
Run Code Online (Sandbox Code Playgroud)

与上述sed有关就地更新的警告同样适用。


使用awk

awk '{ sub("\r$", ""); print }' myitems.csv  # shorter: awk 'sub("\r$", "")+1'
Run Code Online (Sandbox Code Playgroud)

BSD 不awk提供就地更新选项,因此您必须在不同的文件中捕获输出;要使用临时文件并在之后替换原始文件,请使用以下习语:

awk '{ sub("\r$", ""); print }' myitems.csv > tmpfile && mv tmpfile myitems.csv
Run Code Online (Sandbox Code Playgroud)

GNU awk v4.1 或更高版本提供-i inplace就地更新,与上述相同的警告sed适用。


以上所有变体的边缘情况:如果是最后一个字符。在输入文件中恰好是一个\r没有跟随的孤单\n,它也会被替换为\n.


为了完整起见:这里是额外的,可能是次优的解决方案

它们都不提供就地更新,但您可以使用> tmpfile && mv tmpfile myitems.csv上面介绍的习语


使用tr:一个非常简单的解决方案,只需删除所有 \r实例;因此,它只能在\r实例作为\r\n 个序列的一部分出现时使用;然而,通常情况这样:

tr -d '\r' < myitems.csv
Run Code Online (Sandbox Code Playgroud)

使用纯bash代码:注意这会很;像tr解决方案一样,这只能在\r实例作为\r\n序列的一部分出现时使用。

while IFS=$'\r' read -r line; do
  printf '%s\n' "$line"
done < myitems.csv
Run Code Online (Sandbox Code Playgroud)

$IFS是内部字段分隔符,并将其设置为\r导致read将 之前的所有内容(如果存在)读取\r到变量中$line(如果没有\r,则按原样读取该行)。-r阻止read解释\输入中的实例。

边缘情况:如果输入不以 结尾\n则不会打印最后一行- 您可以使用read -r line || [[ -n $line ]].