2016-07-26 95 views
0

我想写一个shell脚本,它可以确定输入文件中的行是以DOS(CR/LF)还是Unix(LF)换行符结尾。如何从DOS脚本中区分DOS换行文件

我该如何做出这个决定?

+0

您可以在您的if []中使用回声“ASCII”,并在您的其他文件 –

+2

中使用echo“CR/LF”提供此信息和更多信息。是否有一个令人信服的理由来重塑它? – John1024

+0

顺便说一句 - 我的编辑在这里是严厉的,但也有必要有一个允许的网站规则的问题。我们非常不满意“请为我编写我的程序”问题 - 一个问题应该专门针对您在尝试实现您的目标时遇到的技术问题。 –

回答

1

一种方法是避免依赖外部工具,如file如下:

#!/bin/bash 
#  ^^^^- important! not /bin/sh, and do not run with "sh scriptname" 

# if given a command-line argument, redirect from it as stdin 
if [ -n "$1" ]; then 
    exec <"$1" || exit 
fi 

# Read a single line from stdin into a variable 
if ! IFS= read -r line; then 
    # we were unable to read a line 
    echo "Invalid or Empty" 
    exit 1 
fi 

# Check whether the last character of that line is a CR 
case $line in 
    *$'\r') echo "DOS" ;; 
    *)  echo "UNIX" ;; 
esac 

这工作,因为在bash(虽然不是POSIX SH),$'\r'是语法回车(CR)字符。由于read会读取第一个看到的LF,因此在DOS文件中,从该文件读取的行中的最后一个字符将是CR。

+0

好的解决方案,但不完全是OP要求的。如果我正确理解这个问题,那么在检查时,文件*是否以LF或CRLF结束*是否在第一个* LF之前是CR。当输入文件是一个二进制文件或带有混合行结尾的文件(某些LF和某些CRLF)或最后一行没有行结束标记的文件时,这会有所不同。 – user1934428

+1

@ user1934428太懒得检查OP的原始问题,但我也将它解释为“每行以......结尾......”,正如主题标题所建议的那样。 – tripleee

+1

@ user1934428克服了我的懒惰,并修正了编辑问题中的歧义。实际上,OP最初询问是否识别文件的结尾。 – tripleee

0

,您可以先

last2=`tail -c 2 your_file | od -x -A n` 

这种存储在变量last2最后两个字节your_file的十六进制表示。唯一的问题是字节顺序。在一个big-endian机器上,它将是0a0d,在一个小端机器0d0a上。

现在你既可以根据您的硬件的存储方式编写测试,或者你可以欺骗和写入

if [ $last2 = 0a0d -o $last2 = 0d0a ] 
then 
    # Cheating! If the file ends in LFCR, it would incorrectly 
    # say that it is CRLF 
    echo File ends in CRLF 
fi 
+0

对于没有最后一行结束标记的DOS文件,这将无法可靠地工作。 – tripleee

+0

的确如此,但是,诚实地说:如果目标是真正地猜测它是否是DOS文件,我认为最安全的方法就是依靠@文件工具,正如@ John1024所建议的那样。即使在你的方法中,如果文件是一个二进制文件,它的流中恰好有0x0d和/或0x0a,我们也会遇到问题。但无论如何,了解为什么需要这种分类将会有所帮助。 – user1934428

1

如果检查的第一行就足够了,像

perl -ne 'exit ($_ =~ /\r$/)' file 

你可以在Bash中做同样的事情;

lffile() { 
    local REPLY 
    read -r <"$1" 
    case $REPLY in *$'\r') return 1;; *) return 0;; esac 
} 

这需要$'\r' Bash> = 3.x的C风格字符串。如果你可以在脚本中可靠地,可移植地嵌入文字回车符,那么你甚至可以使用sh来做这个小改动。下面以一个讨厌的全球持有回车符:

lffile_cr=$(printf '\r') 
lffile() { 
    # local is not POSIX; simply overwrite REPLY 
    read -r <"$1" 
    case $REPLY in *"$lffile_cr") return 1;; *) return 0;; esac 
} 

在最一般的情况下,一个文件可能有混线的结局,但如果我们假设行结尾是一致的(和/或得到一个对于那个不起眼的角落案例,50%的命中或错过率是可以接受的),读第一行就足够了。