【问题标题】:How to remove the CRLF(\r\n) at the end of a line in linux/unix? [duplicate]如何在 linux/unix 中删除一行末尾的 CRLF(\r\n)? [复制]
【发布时间】:2016-05-13 09:38:24
【问题描述】:

我用过

sed 's/\r\n$//' inputFile

但是没有用。不知道为什么

我也试过了

awk '{ printf "%s", $0 }' inputFile

但它只删除 \n 而不是 \r

linux中如何去掉行尾CRLF(\r\n)的具体组合?

附:

鉴于我的问题的具体情况,我认为这不是 this 的重复。我希望删除行尾的 CRLF(\r\n) 。 tr 不起作用,因为tr 要删除的外观不一定在行尾,并且管理员要求不要安装dos2unix。就我而言,sed 's/\r\n$//' inputFile 不起作用,我几乎尝试了this 中的所有可能解决方案。

顺便说一句,tr,要删除的外观不一定在行尾,tr 中的\r\n\r\n 的集合。换句话说,它会删除 \r 中的 \r 在行的中间。

澄清:

我只有一行输入。我希望完全删除 \r\n

【问题讨论】:

  • 尝试 tr -d '\a\b\r' 输入文件
  • 使用 dos2unix,或查看同一问题的数百个答案之一。
  • @123 我不能使用dos2unix也不能安装它,因为管理员不允许它。
  • 's/\r\n$//' 显然不起作用,因为 sed 是行阅读器并且看不到换行符。另外,为什么你会在一行中间有一个回车?
  • 为什么要删除换行符和回车符?这是没有意义的。一个文本文件将是一根长拼接线。对于意味着死亡的脚本。

标签: linux bash unix awk sed


【解决方案1】:

回答最后一条评论:只有一行...纯

read string <InputFile
echo -n "${string%$'\r'}"

解释:read 将按行读取,因此自然地放在尾随 换行。然后${variable%$'\r'} 将删除 1 尾随 CR

查看help read,了解有关这样做的限制和选项:

printf ' foo\\x\r\t bar\r\n' > InputFile
IFS= read -r string <InputFile 
echo -n "${string%$'\r'}" | od -A n -t a -t c
      sp   f   o   o   \   x  cr  ht  sp   b   a   r
           f   o   o   \   x  \r  \t       b   a   r

(我使用-t c -t a,因为第二个更可读,但不明确显示空格。)

这也可以在常规 下工作:

CR=`printf \\\r`
read string <InputFile
echo -n "${string%$CR}"

第一个答案:行尾行分隔符

要在行尾鞭打 CR,请使用:

sed -e 's/\r$//'

在 Unix 的sed 下,行由\n分隔,所以当你不使用N sed 命令时,你可能永远不会在一行中找到\n

但是如果你想合并你所有的行:

sed -ne ':;N;$!b;s/\r\n//g;p'

这将删除所有CRLF,文件末尾除外。 (您可以使用 bash ${var%$'\r\n'}head -c -2 删除)

sed -ne ':;N;$!b;s/\r\n//g;p' | head -c -2

【讨论】:

  • 也不删除换行符。
  • 答案已编辑(无论如何,我不确定您需要...)
  • wrt This will drop all CRLF except at very end of file. - OP 有一行,所以文件末尾的 CRLF 是他唯一需要删除的。
  • @EdMorton 好的,对于 单行 输入,事情变得非常简单......答案已编辑!
  • 您发布的更简单的解决方案将不希望地去除所有前导和尾随空格并从行中删除所有反斜杠。在您使用printf ' foo\\xbar\r\n' &gt; InputFile 创建的文件上试一试。您至少需要将 IFS 设置为 null 并添加 -r 选项以读取:IFS= read -r string &lt;InputFile。使用 shell 处理文本从来没有看起来那么简单,因为这不是 shell 的设计目的(例如,请参阅 unix.stackexchange.com/questions/169716/…
【解决方案2】:

Perl 具有相当的可移植性,并且可以很好地处理这个问题。

perl -pe 's/\r\n//' file

这将留下任何单独的\r\n,但如果它们按此特定顺序一个接一个地出现,则将它们都删除。

【讨论】:

    【解决方案3】:

    一个完全不同的解决方案,只是为了好玩(但它有效)。假设你已经安装了xxd

    xxd -ps -c 1 inputFile |
        awk 'BEGIN {prev=""} {if ($0=="0a" && prev=="0d") {prev="skip"} else { if (prev!="skip" && prev!="") {print prev} prev=$0 } } END {if (prev!="") {print prev}}' |
        xxd -r -ps
    

    基本上,它将文件转换为每个字符的 2 位十六进制,然后使用 awk 对其进行过滤,连续查找 2 个匹配行(“0d”“0a”,即\r\n)并跳过它们。

    但实际上,我只推荐使用 python 或 perl。其中之一应该已经在系统上。例如:

    <inputFile python2 -c 'import sys; sys.stdout.write(sys.stdin.read().replace("\r\n",""))'
    

    【讨论】:

      【解决方案4】:

      如果它只有一行并且你知道最后肯定有\r\n,你可以使用head并去掉最后2个字节:

      head -c -2 inputFile
      

      【讨论】:

        【解决方案5】:

        使用 GNU awk 实现多字符 RS 和二进制模式:

        $ od -tc file
        0000000   f   o   o       b   a   r  \r  \n
        0000011
        
        $ awk -v BINMODE=3 -v RS='\r\n' -v ORS= '1' file | od -tc
        0000000   f   o   o       b   a   r
        0000007
        

        这就是为什么你需要设置BINMODE=3

        $ awk '1' file | od -tc
        0000000   f   o   o       b   a   r  \n
        0000010
        
        $ awk -v BINMODE=3 '1' file | od -tc
        0000000   f   o   o       b   a   r  \r  \n
        0000011
        

        在某些平台(例如 cygqwin)上没有它,gawk 甚至看不到 \r,底层 C 原语将其删除。

        【讨论】:

          【解决方案6】:

          你可以使用 GNU awk :

          之前:

          0000000   S   i   n   g   o  \n   D   i   n   g   o  \n  \r   P   i   n
          0000020   g   o  \r   M   i   n   g   l   o  \r  \n   S   i   n   g   l
          0000040   i  \r  \n
          0000043
          

          操作

          $ awk 'BEGIN{RS="^$"}{printf "%s",gensub(/\r\n/,"","g")}' file1 > file2  && mv file2 file1
          

          之后

          $ od -tc file1
          0000000   S   i   n   g   o  \n   D   i   n   g   o  \n  \r   P   i   n
          0000020   g   o  \r   M   i   n   g   l   o   S   i   n   g   l   i
          0000037
          

          如果您希望将CRLF 替换为LF,您可能希望将gensub(/\r\n/,"","g") 更改为gensub(/\r\n/,"\n","g")

          注意事项:

          1. 你不应该在 awk 中使用print,因为它会在最后生成一个LF。而是使用带有格式字符串的printf
          2. 我已根据@ed-morton 在comment#1 中建议的更改对答案进行了编辑。此外,此评论包含一些可能有用的特定于平台的信息。

          【讨论】:

          • 您应该提到这是 gawk/mawk 特有的,因为 gensub() 并且设置 RS="\0" 是不可移植的(相反,您需要使用 RS="^$" 一次读取整个文件)并且它不适用于所有平台(例如 cygwin),因为在某些底层 C 原语中,gawk 用于读取文件会在 gawk 看到它们之前剥离 \rs,因此您需要设置 -v BINMODE=3 以阻止这种情况发生。
          • @EdMorton :我从来不知道我们可以设置RS=^$,谢谢你的提示。将此纳入我的答案。 :D
          • 是的,它保证可以在任何接受多字符 RS 的 awk 中工作,因为这意味着 start of string then end of string 在整个文件中,所以它可以匹配文件内容的唯一方法是文件是空的。因此,它为您提供了一个记录分隔符,它不能匹配非空文件中的任何字符串,因此保证将整个文件作为单个记录读取。 \0 的使用是命中注定的,请参阅 gnu.org/software/gawk/manual/gawk.html#gawk-split-records
          【解决方案7】:

          我个人认为如果不熟悉perl或python,下面的方法也不错

          sed 's/\r$//' inputFile | awk '{printf "%s", $0}'
          

          【讨论】:

            【解决方案8】:

            要从 DOS 行中创建 unix 行,您只需删除回车符 (CR)。 sed命令如下:

            sed 's/\r//g' 输入文件 > 输出文件

            试一试。

            【讨论】:

            • 这将产生与tr -d \\r 相同的结果:又名:不仅在行尾...
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2014-02-15
            • 1970-01-01
            • 2017-09-18
            • 1970-01-01
            • 2016-03-21
            • 2014-06-17
            • 2014-05-14
            相关资源
            最近更新 更多