【问题标题】:Remove \r (CR) from CSV从 CSV 中删除 \r (CR)
【发布时间】: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 尝试了很多选项,但没有任何效果。

有什么想法吗?

【问题讨论】:

    标签: macos csv sed newline


    【解决方案1】:

    库存实用程序解决方案

    注意:除非另有说明(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 ]] 来解决这个问题。

    【讨论】:

      【解决方案2】:

      试试这个,它会解决你的问题。

      dos2unix myitems.csv myitems.csv
      

      【讨论】:

      • dos2unix 在 OSX 上默认不可用,但Homebrew 用户可以通过brew install dos2unix 获取。但是:dos2unix 默认会就地 转换文件,因此您可能只需要dos2unix myitems.csv(第二次指定文件只会尝试再次转换它)。相比之下,如果您想写入不同的输出文件,请使用dos2unix -n myitems.csv new-myitems.csv(适用于 OSX 和 Linux 版本)。
      【解决方案3】:

      试试 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
      

      【讨论】:

      • 我认为 OP 想要朝相反的方向前进 - DOS -> Unix - 原始措辞不清楚,但 ^M 的存在出现在 cat -v 的输出中以及OSX 参考建议它是关于删除 \r (CR) 字符。
      猜你喜欢
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多