Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Git Bash is a nice bash shell you get in Windows as part of the installation of Git. It comes with other typical unix tools bundled inside, such as grep, sed, awk, perl. It doesn't have the file command.

In this shell, I want to detect files that have DOS-style line endings. I thought this command would work but it doesn't:

grep -l ^M$ *

It doesn't work, even files that don't have CR line endings match. For example if I create 2 sample files hello.unix and hello.dos, I can confirm with wc that hello.unix has 6 characters and hello.dos has 7 characters because of the extra CR, but both files match with grep. That is:

$ cat hello.*
hello
hello

$ wc hello.*
      1       1       7 hello.dos
      1       1       6 hello.unix
      2       2      13 total

$ grep -l ^M hello.*
hello.dos
hello.unix

Is this a bug in the grep implementation or what? Is there another way to find all files with DOS-style line endings?

share|improve this question
    
I don't know what Git bash is, does it have the 'file' command? –  EightBitTony Oct 11 '12 at 11:10
1  
Are you aware of git config core.autocrlf input? –  cjm Oct 11 '12 at 17:21
    
May I wonder why xargs and not just use the exec option of find? Doesn't it exist in git bash? –  David Kohen Oct 11 '12 at 19:22
    
@DavidKohen you're right, -exec would work too. But it's irrelevant for the question, so I removed that now. –  janos Oct 12 '12 at 7:59
    
@cjm This is not necessarily for files under version control but any files –  janos Oct 12 '12 at 8:00
add comment

4 Answers 4

EDIT: Silly me. Of course ^M is CR; and your command should work (works on my system). However, you need to type Ctrl-V Ctrl-M to get the literal '\r'/CR (and not two characters, ^ and M).

Alternatives:

Do this:

find dir -type f -print0 | xargs -0 grep -l `printf '\r\n'`

Or this:

find dir -type f -print0 | xargs -0 grep -lP '\r\n'

You can also use the file utility (not sure if it comes with GIT bash):

find dir -type f -print0 | xargs -0 file | grep CRLF
share|improve this answer
    
Yeah it should normally work, but it does not work in Git Bash. Unfortunately none of your tips work: the printf doesn't work, grep doesn't have -P flag, and there is no file command in Git Bash... Any other ideas? –  janos Oct 11 '12 at 10:01
    
How about `echo -e '\r\n'`? Should do the same as printf. –  January Oct 11 '12 at 10:13
    
Same as printf, none of the files match that way. –  janos Oct 11 '12 at 12:07
    
Um, so most likely a bug. Do you have a C compiler installed? I can write you a little C program that should work. –  January Oct 11 '12 at 12:41
    
No gcc or cc comes with Git Bash. I don't want to install cygwin. So, thanks, but nevermind. My workaround is to convert all files which I suspect to have CR line-endings. The files which don't have will not be changed so it should be ok, it's just an ugly solution. –  janos Oct 11 '12 at 13:00
show 3 more comments

I don't know about git bash, but maybe

if [ "$(tr -cd '\r' < file | wc -c)" -gt 0 ]; then
  echo there are CR characters in there
fi

would work. The idea being not to use text utilities that may treat the CR and LF characters specially.

If that doesn't work, then maybe

if od -An -tx1 < file | grep -q 0d; then
  echo there are CR characters in there
fi

To hook into find:

find . -type f -exec sh -c 'od -An -tx1 < "$1" | grep -q 0d' sh {} \; -print
share|improve this answer
    
No od in Git Bash. But the tr trick is pretty clever and it works! There is just one relatively minor issue with it: it detects CR anywhere in the file, but I need to detect CR at line endings. You have lead me to the solution, using sed instead of tr. See my answer for more details, and thanks again! –  janos Oct 12 '12 at 8:44
    
When is CR used outside of line endings? –  David Kohen Oct 12 '12 at 11:46
add comment
up vote 1 down vote accepted

@sch has lead me to this solution:

sed -bne '/\r$/ {p;q}' < /path/to/file | grep -q .

This exits with TRUE if the file has any lines ending with CR. To hook this into find:

find /path/to/ -type f -exec sh -c 'sed -bne "/\r$/ {p;q}" < "$1" | grep -q .' sh {} \; -print

And I think I know why grep -l ^M hello.* doesn't work in this shell: it seems that in Git Bash ^M characters are removed from all command line arguments, so grep never actually receives the character, and therefore all files match. This behavior is not only on the command line, but in shell scripts too.

So the key is to express the ^M character with other symbols, such as \r, instead of literally.

share|improve this answer
add comment

You can solve it using Python:

import string
import fileinput

for line in fileinput.input():
    if (string.find(line,"\r")!=-1):
        print fileinput.filename()
        fileinput.nextfile()

This small python file would behave just like you would expect the grep (get a filename list and print the names with CR in them).

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.