Answers:
如果目标只是为了避免影响时间戳,请dos2unix
使用-k
或--keepdate
选项将时间戳保持不变。它仍然需要进行写操作以制作临时文件并将其重命名,但是您的时间戳不会受到影响。
如果不接受文件的任何修改,则可以从此答案中使用以下解决方案。
find . -not -type d -exec file "{}" ";" | grep CRLF
find ... -exec file ... | grep CRLF
与DOS行结束一个文件(即字节0D 0A)“将让你这样的:./1/dos1.txt: ASCII text, with CRLF line terminators
正如你可以看到这个包含实际的字符串CRLF,因此通过匹配grep
寻找简单的字符串CRLF
您可以尝试grep
输入八进制的CRLF代码:
grep -U $'\015' myfile.txt
或十六进制:
grep -U $'\x0D' myfile.txt
grep
用法,因为它使我可以轻松地使用目录列出所有此类文件,grep -lU $'\x0D' *
并将输出传递给xargs
。
由于版本7.1
dos2unix具有一个-i
,--info
选项,以获取有关换行符的信息。您可以使用dos2unix本身来测试哪些文件需要转换。
例:
dos2unix -ic *.txt | xargs dos2unix
grep
):计算包含回车符的行:
[[ $(grep -c $'\r' myfile.txt) -gt 0 ]] && echo dos
计算以回车结尾的行:
[[ $(grep -c $'\r$' myfile.txt) -gt 0 ]] && echo dos
这些通常是等效的;在行的内部(即不在末尾)回车的情况很少。
更高效:
grep -q $'\r' myfile.txt && echo dos
这样更有效
grep -c
需要读取整个文件,以计算模式的所有出现次数,同时grep -q
可以在看到模式的第一次出现时退出。笔记:
-U
选项(即use -cU
或-qU
),因为GNU会grep
猜测该文件是否为文本文件。如果它认为文件是文本,则它会忽略行尾的回车符,以使$
正则表达式“正确”工作,即使正则表达式为\r$
!指定-U
(或--binary
)会否定此猜测,导致grep
将文件视为二进制文件,并将数据原样传递给匹配机制,且CR末尾保持完整。grep … $'\r\n' myfile.txt
,因为grep
将其\n
视为模式定界符。就像grep -E 'foo|'
查找包含foo
或为空字符串的行一样,
grep $'\r\n'
查找包含\r
或为空字符串的行,并且每行都匹配一个空字符串。file
):[[ $(file myfile.txt) =~ CRLF ]] && echo dos
因为file
报告如下:
myfile.txt: UTF-8 Unicode text, with CRLF line terminators
更安全的变体:
[[ $(file -b - < myfile.txt) =~ CRLF ]] && echo dos
哪里
file -b
仅输出文件类型,而不输出文件名。没有这一点,一个文件,其名称包含字符CRLF
会触发误报。file - < filename
即使filename
以开头也可以工作-
。
请参阅Bash脚本:检查文件是否为文本文件。请注意,file
在非英语语言环境中检查来自的输出可能不起作用。
"$(echo -e '\r')"
用更简单的替换$'\r'
,尽管我个人会$'\r\n'
减少误报的数量。
grep $'\r\n'
似乎与我系统上的所有文件匹配...
grep -U $'\r$'
,以防止grep
尝试猜测行尾。
-q
如果找到匹配项,则可以使用它来设置返回码,而不是-c
需要额外的检查。我个人喜欢您的第二个解决方案,尽管它高度依赖于异想天开,file
并且可能不适用于非英语语言环境。
采用 cat -A
$ cat file
hello
hello
现在,如果此文件是在* NIX系统中制作的,它将显示
$ cat -A file
hello$
hello$
但是,如果此文件是在Windows中制作的,它将显示
$ cat -A file
hello^M$
hello
^M
代表CR
和$
代表LF
。请注意,Windows没有使用以下命令保存最后一行CRLF
这也不会更改文件内容。
-A
为了猫。cat -A file | less
如果文件太大,可以使用一个技巧。我敢肯定,必须检查文件结尾以查找特别长的文件并不少见。(按一下q
即可离开)
一个bash功能为您服务:
# return 0 (true) if first line ends in CR
isDosFile() {
[[ $(head -1 "$1") == *$'\r' ]]
}
然后你可以做类似的事情
streamFile () {
if isDosFile /tmp/foo.txt; then
sed 's/\r$//' "$1"
else
cat "$1"
fi
}
streamFile /tmp/foo.txt | process_lines_without_CR
如果文件具有DOS / Windows风格的CR-LF行尾,则使用基于Unix的工具查看文件时,您会在每行末尾看到CR('\ r')字符。
该命令:
grep -l '^M$' filename
将打印filename
,如果该文件包含一个或多个行与Windows风格的行结束符,并且如果它不将打印什么。除了^M
必须是原义的回车字符外,通常在终端中输入Ctrl+,V然后输入Enter
(或Ctrl+ V,然后再Ctrl+ M)。bash shell使您可以将文字回车符写为$'\r'
(在此处记录),因此您可以编写:
grep -l $'\r$' filename
其他外壳可以提供类似的功能。
您可以改用其他工具:
awk '/\r$/ { exit(1) }' filename
如果文件包含任何Windows样式的行尾,它将以1
(设置$?
为1
)状态退出,如果文件不包含Windows样式的行尾,则退出状态0
,使其在shell if
语句中很有用(请注意缺少[
方括号]
):
if awk '/\r$/ { exit(1) }' filename ; then
echo filename has Unix-style line endings
else
echo filename has at least one Windows-style line ending
fi
文件可以包含Unix样式和Windows样式的行尾混合。我在这里假设您要检测具有任何 Windows样式的行尾的文件。
$'\r'
,在命令行中使用bash(和其他一些shell)对回车编码,如对此问题的其他答案所述。
用途file
:
$ file README.md
README.md: ASCII text, with CRLF line terminators
$ dos2unix README.md
dos2unix: converting file README.md to Unix format...
$ file README.md
README.md: ASCII text
我一直在用
cat -v filename.txt | diff - filename.txt
这似乎有效。我发现输出比
dos2unix < filename.txt | diff - filename.txt
如果dos2unix
由于某种原因无法安装,它也很有用。