Làm thế nào để bạn tìm kiếm các tệp chứa kết thúc dòng dos (CRLF) với grep trên Linux?


125

Tôi muốn tìm kiếm các tệp chứa kết thúc dòng dos với grep trên Linux. Một cái gì đó như thế này:

grep -IUr --color '\r\n' .

Ở trên dường như phù hợp với nghĩa đen rnmà không phải là những gì mong muốn.

Đầu ra của cái này sẽ được dẫn qua xargs thành todos để chuyển crlf thành lf như thế này

grep -IUrl --color '^M' . | xargs -ifile fromdos 'file'

2
Bạn đã thử dos2unix chưa? Nó tự động sửa kết thúc dòng.
sblundy

Tôi không chắc lắm nhưng tôi có một sự khác biệt giữa trích dẫn mẫu bên trong 'và ". Afaik trong các mẫu được đặt trong' các chuỗi thoát được hiểu là chuỗi thích hợp nên '\ r' sẽ tương đương với" \ r "và" \ r "không có tương đương (ít nhất là trong ký hiệu đó) với '.
Anticom

Anticom: Bạn đã đúng trong trường hợp này rằng sự khác biệt giữa 'và "là không liên quan, tuy nhiên, nhìn chung chúng khác biệt vì' các chuỗi được bao quanh là trích dẫn yếu và" được trích dẫn mạnh mẽ. Điều lớn nhất tôi tận dụng là $ mở rộng hoặc `` không mở rộng trong các chuỗi trích dẫn yếu. Xem bash-tin tặc về trích dẫn để biết thêm.
bschlueter

4
Cách dễ nhất là sử dụng hiện đại dos2unixvới -icchuyển đổi. Đối với các tệp tin bạn có thể tìm kiếm với unix2dos -ic. Nó không sửa đổi các tập tin. Chỉ báo cáo.
gavenkoa

3
vì đây là câu trả lời hàng đầu cho bất kỳ câu hỏi nào liên quan đến kết thúc / vận chuyển dòng Windows trên Linux, tôi nghĩ rằng đáng lưu ý rằng bạn có thể thấy chúng trong thiết bị đầu cuối bằng lệnh cat -v somefile.txt; chúng hiển thị dưới dạng^M
user5359531

Câu trả lời:


121

Sử dụng Ctrl+ V, Ctrl+ Mđể nhập ký tự Vận chuyển bằng chữ vào chuỗi grep của bạn. Vì thế:

grep -IUr --color "^M"

sẽ hoạt động - nếu ^Mcó CR theo nghĩa đen mà bạn nhập như tôi đề xuất.

Nếu bạn muốn danh sách các tập tin, bạn cũng muốn thêm -ltùy chọn.

Giải trình

  • -I bỏ qua các tập tin nhị phân
  • -Ungăn grep để loại bỏ các ký tự CR. Theo mặc định, nó sẽ làm điều đó nếu nó quyết định đó là một tệp văn bản.
  • -r đọc tất cả các tập tin dưới mỗi thư mục đệ quy.

3
Là một cách nhanh chóng có thể hoạt động nhưng tôi nghĩ giải pháp đọc của con người sẽ là: grep $ '\ r' / bash shell only / hoặc grepprintf '\r'
akostadinov

5
@akostadinov +1, nhưng backticks đã được giải thích từ nhận xét của bạn;) Nói cách khác, tùy chọn thứ hai sẽ là grep $(printf '\r'). Nhưng đối với hầu hết các ứng dụng thực tế liên quan đến bash, tôi sẽ gắn bó $'\r'.
jankes

3
Lưu ý: Tùy chọn -Unày chỉ phù hợp với Windows (hoặc cygwin), nhưng nó rất quan trọng. Trên Windows, lệnh sẽ không hoạt động nếu không có nó.
sleske

3
Điểm của tùy chọn là -Igì? Theo hướng dẫn, dường như các tệp nhị phân được coi là không khớp. Không nên kết hợp -I-U(thực thi loại nhị phân) dẫn đến tất cả các tệp được coi là không khớp?
Jāni Elmeris

3
Bạn đề cập đến cờ '-l' dưới dạng tùy chọn bổ trợ, nhưng tôi nghĩ rằng nó nên được đưa vào câu trả lời chính vì về cơ bản câu hỏi yêu cầu danh sách các tệp. Ngoài ra, nó dẫn đến một tìm kiếm nhanh hơn.
Array_sea

166

grep có lẽ không phải là công cụ bạn muốn cho việc này. Nó sẽ in một dòng cho mỗi dòng phù hợp trong mỗi tệp. Trừ khi bạn muốn, giả sử, chạy todos 10 lần trên tệp 10 dòng, grep không phải là cách tốt nhất để thực hiện. Sử dụng find để chạy tệp trên mỗi tệp trong cây, sau đó chuyển qua đó cho "CRLF" sẽ giúp bạn có một dòng đầu ra cho mỗi tệp có kết thúc dòng kiểu dos:

find . -not -type d -exec file "{}" ";" | grep CRLF

sẽ giúp bạn có được một cái gì đó như:

./1/dos1.txt: ASCII text, with CRLF line terminators
./2/dos2.txt: ASCII text, with CRLF line terminators
./dos.txt: ASCII text, with CRLF line terminators

Tôi đã phá vỡ điều này, nhưng dù sao cũng cảm ơn. grep -IUrl --color '^M' . | xargs -ifile fromdos 'file'
Tim Abell

5
Tùy chọn -l để grep bảo nó chỉ liệt kê các tệp (một lần) thay vì liệt kê các kết quả khớp trong mỗi tệp.
pjz

7
Không phải là một giải pháp tốt, để phụ thuộc vào hành vi đó (không có giấy tờ, hướng đến tiêu dùng của con người) của filechương trình. Điều này rất mong manh. Ví dụ (chỉ một): nó không hoạt động với các tệp XML, filebáo cáo XML document textbất kể loại dòng mới.
leonbloy

1
@leonbloy, tùy chọn này dường như là chữ thường -m /dev/nulltrên find (GNU findutils) 4.4.2(Ubuntu 12.04) của tôi.
EarlCrapstone

7
Tôi thích câu trả lời này tốt nhất. Tôi chỉ đơn giản là đã làmfind . -type f | xargs file | grep CRLF
brianz 16/1/2015

58
grep -IUlr $'\r'

Explshell.com - grep -IUlr


11
Cảm ơn! Để rõ ràng cho những người đến sau, hướng dẫn bash nói "Các từ có dạng $ 'chuỗi' được xử lý đặc biệt. Từ này mở rộng thành chuỗi, với các ký tự thoát dấu gạch chéo ngược được thay thế theo quy định của tiêu chuẩn ANSI C." (xem thêm danh sách mã được hỗ trợ này )
Sean Gugler

5
Vì vậy, bash này là cụ thể? Nó cần được lưu ý nếu nó là.
cubuspl42

đối với git với autocrlf xấu, tôi sẽ sử dụng: grep -IUlrZ $ '\ r' | xargs -0 sed -zbi 's / \ r // g'
buzard

16

Nếu phiên bản grep của bạn hỗ trợ tùy chọn -P (--perl-regapi) , thì

grep -lUP '\r$'

có thể được sử dụng.


8
# list files containing dos line endings (CRLF)

cr="$(printf "\r")"    # alternative to ctrl-V ctrl-M

grep -Ilsr "${cr}$" . 

grep -Ilsr $'\r$' .   # yet another & even shorter alternative

3

Truy vấn là tìm kiếm ... Tôi có một vấn đề tương tự ... ai đó đã gửi các kết thúc dòng hỗn hợp vào kiểm soát phiên bản, vì vậy bây giờ chúng tôi có một loạt các tệp có 0x0d 0x0d 0x0akết thúc dòng. Lưu ý rằng

grep -P '\x0d\x0a'

tìm thấy tất cả các dòng, trong khi

grep -P '\x0d\x0d\x0a'

grep -P '\x0d\x0d'

không tìm thấy dòng nào nên có thể có một cái gì đó "khác" đang diễn ra bên trong grep khi nói đến các mẫu kết thúc dòng ... thật không may cho tôi!


3

Bạn có thể sử dụng lệnh tập tin trong unix. Nó cung cấp cho bạn mã hóa ký tự của tệp cùng với các đầu cuối dòng.

$ file myfile
myfile: ISO-8859 text, with CRLF line terminators
$ file myfile | grep -ow CRLF
CRLF  

1

Nếu, giống như tôi, unix tối giản của bạn không bao gồm các chi tiết như lệnh tập tin và dấu gạch chéo ngược trong biểu thức grep của bạn chỉ không hợp tác, hãy thử điều này:

$ for file in `find . -type f` ; do
> dump $file | cut -c9-50 | egrep -m1 -q ' 0d| 0d'
> if [ $? -eq 0 ] ; then echo $file ; fi
> done

Những sửa đổi bạn có thể muốn thực hiện ở trên bao gồm:

  • điều chỉnh lệnh find để chỉ định vị các tệp bạn muốn quét
  • thay đổi lệnh dump thành od hoặc bất kỳ tiện ích kết xuất tập tin nào bạn có
  • xác nhận rằng lệnh cắt bao gồm cả không gian đầu và cuối cũng như đầu ra ký tự thập lục phân từ tiện ích kết xuất
  • giới hạn đầu ra kết xuất ở 1000 ký tự đầu tiên hoặc lâu hơn để đạt hiệu quả

Ví dụ: một cái gì đó như thế này có thể làm việc cho bạn bằng cách sử dụng od thay vì dump :

 od -t x2 -N 1000 $file | cut -c8- | egrep -m1 -q ' 0d| 0d|0d$'

1

dos2unix có một tùy chọn thông tin tệp có thể được sử dụng để hiển thị các tệp sẽ được chuyển đổi:

dos2unix -ic /path/to/file

Để làm điều đó một cách đệ quy bạn có thể sử dụng bash's globstartùy chọn, trong đó cho vỏ hiện tại được kích hoạt với shopt -s globstar:

dos2unix -ic **      # all files recursively
dos2unix -ic **/file # files called “file” recursively

Ngoài ra, bạn có thể sử dụng findcho điều đó:

find -exec dos2unix -ic {} +            # all files recursively
find -name file -exec dos2unix -ic {} + # files called “file” recursively
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.