如何查找Windows行末(EOL)字符

13

我有数百GB的数据需要使用Cygwin中的unix paste工具进行拼接,但如果文件中存在Windows EOL字符,则该工具无法正常工作。这些数据可能具有或不具有Windows EOL字符,并且如果不需要运行dos2unix,则不想花费时间。

因此,我的问题是,在Cygwin中,如何确定这些文件是否具有Windows EOL CRLF字符?

我尝试创建一些测试数据并运行:

sed -r 's/\r\n//' testdata.txt

但是,无论是否运行了dos2unix,它似乎都匹配。

谢谢。

8个回答

21

file(1) 工具知道区别:

$ file * | grep ASCII
2:                                       ASCII text
3:                                       ASCII English text
a:                                       ASCII C program text
blah:                                    ASCII Java program text
foo.js:                                  ASCII C++ program text
openssh_5.5p1-4ubuntu5.dsc:              ASCII text, with very long lines
windows:                                 ASCII text, with CRLF line terminators

file(1)已被优化,尽可能地尝试读取文件的少量内容,因此您可能会很幸运地大幅减少查找和修复CRLF终止符时需要执行的磁盘IO量。

请注意,某些情况下CRLF应保持不变:捕获SMTP时将使用CRLF。但这取决于您。 :)


如果结果显示“ASCII文本,具有非常长的行且没有行终止符”,该怎么办? - Stephen Turner
嘿,一行非常长且没有任何行终止符可能是“paste(1)”的尴尬输入,但也许“file(1)”放弃得太快了?也许这些行比它检查的区域更长。 (快速查看file的源代码(src / file.h)似乎检查256千字节(HOWMANY),因此听起来您的输入确实缺少非常长的行终止符。) - sarnold

4
#!/bin/bash
for i in $(find . -type f); do
        if file $i | grep CRLF ; then
                echo $i
                file $i
                #dos2unix "$i"
        fi
done

当你准备好转换它们时,请取消注释 "#dos2unix "$i""。


3
你可以使用 file 命令来查找:
file /mnt/c/BOOT.INI 
/mnt/c/BOOT.INI: ASCII text, with CRLF line terminators

在这里,CRLF是一个重要的值。


2
如果你期望退出代码与 sed 不同,那么它不会。它将根据匹配执行替换或不执行替换。除非出现错误,否则退出代码将为真。
然而,你可以从 grep 中获得可用的退出代码。
#!/bin/bash
for f in *
do
    if head -n 10 "$f" | grep -qs $'\r'
    then
        dos2unix "$f"
    fi
done

2

使用文件模式过滤的递归grep

grep -Pnr --include=*file.sh '\r$' .

输出文件名、行号和行内容

./test/file.sh:2:here is windows line break

2

您可以使用dos2unix的-i选项来获取关于DOS Unix Mac行尾符(按顺序),BOM和文本/二进制文件的信息,而无需转换文件。

$ dos2unix -i *.txt
    6       0       0  no_bom    text    dos.txt
    0       6       0  no_bom    text    unix.txt
    0       0       6  no_bom    text    mac.txt
    6       6       6  no_bom    text    mixed.txt
   50       0       0  UTF-16LE  text    utf16le.txt
    0      50       0  no_bom    text    utf8unix.txt
   50       0       0  UTF-8     text    utf8dos.txt

使用“c”标志,dos2unix将报告需要转换的文件,即拥有DOS行结束符的文件。要报告所有具有DOS行结束符的txt文件,您可以执行以下操作:

dos2unix -c *.txt
$ dos2unix -ic *.txt
dos.txt
mixed.txt
utf16le.txt
utf8dos.txt

若要仅转换这些文件,您只需执行以下操作:

dos2unix -ic *.txt | xargs dos2unix

如果需要递归遍历目录,您可以使用以下代码:

find -name '*.txt' | xargs dos2unix -ic | xargs dos2unix

另请参阅dos2unix的man页面。


1
感谢您提供使用file(1)命令的提示,但它确实需要更多的细化。我遇到了这样一种情况,不仅纯文本文件,而且一些“.sh”脚本也有错误的eol。而“file”无论eol如何都会报告它们的情况如下:
xxx/y/z.sh: application/x-shellscript

因此,“file -e soft”选项是必需的(至少对于Linux):

bash$ find xxx -exec file -e soft {} \; | grep CRLF

这将在目录xxx及其子目录中查找所有带有DOS行尾的文件。


1
如上所述,“file”解决方案可行。也许以下代码片段可以帮助您。
#!/bin/ksh
EOL_UNKNOWN="Unknown"       # Unknown EOL
EOL_MAC="Mac"               # File EOL Classic Apple Mac  (CR)
EOL_UNIX="Unix"             # File EOL UNIX               (LF)
EOL_WINDOWS="Windows"       # File EOL Windows            (CRLF)
SVN_PROPFILE="name-of-file" # Filename to check.
...

# Finds the EOL used in the requested File
# $1 Name of the file (requested filename)
# $r EOL_FILE set to enumerated EOL-values.
getEolFile() {
    EOL_FILE=$EOL_UNKNOWN

    # Check for EOL-windows
    EOL_CHECK=`file $1 | grep "ASCII text, with CRLF line terminators"`
    if [[ -n $EOL_CHECK ]] ; then
       EOL_FILE=$EOL_WINDOWS
       return
    fi

    # Check for Classic Mac EOL
    EOL_CHECK=`file $1 | grep "ASCII text, with CR line terminators"`
    if [[ -n $EOL_CHECK ]] ; then
       EOL_FILE=$EOL_MAC
       return
    fi

    # Check for Classic Mac EOL
    EOL_CHECK=`file $1 | grep "ASCII text"`
    if [[ -n $EOL_CHECK ]] ; then
       EOL_FILE=$EOL_UNIX
       return
    fi

    return
   } # getFileEOL   
   ...

   # Using this snippet
   getEolFile $SVN_PROPFILE
   echo "Found EOL: $EOL_FILE"
   exit -1

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接