如何检查文本文件的行尾以查看它是 Unix 还是 DOS 格式?

5
我需要将文本文件转换为dos格式(每行结尾都是0x0d0x0a,而不仅仅是0x0a),如果文件是Unix格式(每行结尾只有0x0a)。
我知道如何转换它(sed 's/$/^M/'),但不知道如何检测文件的行尾字符。
我正在使用ksh。
任何帮助都将不胜感激。
[更新]: 有点想通了,这是我的ksh脚本来进行检查。
[qiangxu@host:/my/folder]# cat eol_check.ksh
#!/usr/bin/ksh

if ! head -1 $1 |grep ^M$ >/dev/null 2>&1; then
  echo UNIX
else
  echo DOS
fi

在上述脚本中,应该使用Ctrl-VCtrl-Mvi中插入^M。想知道是否有更好的方法。
6个回答

10

只需使用file命令即可。 如果文件末尾包含CR LF行,会通过注释打印出以下内容: 'ASCII text, with CRLF line terminators'

例如:

if file  myFile | grep "CRLF"  > /dev/null 2>&1;
  then
  ....
fi

2
然而,在我的AIX机器上,ksh只告诉我“test.txt:ascii文本”,无论在test.txt中使用什么样的行尾。它不会告诉我是否包含CRLF。 - Qiang Xu

6
最新的(7.1)版本的dos2unix(和unix2dos)命令与Cygwin和一些最近的Linux发行版一起安装,具有一个方便的--info选项,可以打印每个文件中不同类型换行符的计数。这是dos2unix 7.1(2014-10-06)http://waterlan.home.xs4all.nl/dos2unix.html 从手册页面中得知:
--info[=FLAGS] FILE ...
       Display file information. No conversion is done.

The following information is printed, in this order: 
number of DOS line breaks, number of Unix line breaks, number of Mac line breaks, byte order mark, text or binary, file name.

       Example output:
            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
            2     418     219  no_bom    binary  dos2unix.exe

Optionally extra flags can be set to change the output. One or more flags can be added.
       d   Print number of DOS line breaks.
       u   Print number of Unix line breaks.
       m   Print number of Mac line breaks.
       b   Print the byte order mark.
       t   Print if file is text or binary.
       c   Print only the files that would be converted.

With the "c" flag dos2unix will print only the files that contain DOS line breaks, unix2dos will print only file names that have Unix line breaks.

因此:
if [[ -n $(dos2unix --info=c "${filename}") ]] ; then echo DOS; fi

相反的是:
if [[ -n $(unix2dos --info=c "${filename}") ]] ; then echo UNIX; fi

2
if awk  '/\r$/{exit 0;} 1{exit 1;}' myFile
then
  echo "is DOS"
fi

1

我无法在AIX上进行测试,但请尝试:

if [[ "$(head -1 filename)" == *$'\r' ]]; then echo DOS; fi

它对我不起作用,总是说文件是UNIX格式,而实际上文件是DOS格式。 - Qiang Xu

1
你可以简单地从所有行中删除任何现有的回车符,然后在所有行末添加回车符。那么,无论输入文件的格式如何,输出格式始终为DOS格式。
sed 's/\r$//;s/$/\r/'

那是一种出路。但\r不起作用。它需要被替换为^M(在vi的插入模式下使用Ctrl-VCtrl-M)。然而,我不想一直这样做。有没有一种方法可以检查文本文件的行尾字符? - Qiang Xu
@QiangXu - 我不是sed的常规用户,我更多地使用Windows,所以我不确定。但我认为你需要正则表达式的后顾特性,而我不认为sed支持该特性。 - dbenham

0

我可能晚了一步,但我遇到了同样的问题,我不想在我的脚本中放置特殊的^M字符(我担心某些编辑器可能无法正确显示特殊字符,或者某些后续程序员可能将其替换为2个普通字符:^和M...)。

我找到的解决方案是将特殊字符提供给grep,让shell将其转换为十六进制值:

if head -1 ${filename} | grep $'[\x0D]' >/dev/null
then
  echo "Win"
else
  echo "Unix"
fi

很遗憾,我无法在ksh中使$'[\x0D]'构造工作。

在ksh中,我发现了这个:

if head -1 ${filename} | od -x | grep '0d0a$' >/dev/null
then
  echo "Win"
else
  echo "Unix"
fi

od -x会以十六进制代码显示文本。'0d0a$'是CR-LF的十六进制代码(DOS-Win行终止符)。Unix行终止符是'0a00$'


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