Bagaimana Anda mencari file yang berisi akhir baris dos (CRLF) dengan grep di Linux?


126

Saya ingin mencari file yang berisi akhir baris dos dengan grep di Linux. Sesuatu seperti ini:

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

Hal di atas sepertinya cocok untuk literal rnyang bukan yang diinginkan.

Output dari ini akan disalurkan melalui xargs ke todos untuk mengubah crlf ke lf seperti ini

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

2
Sudahkah Anda mencoba dos2unix ? Ini memperbaiki ujung baris secara otomatis.
sblundy

Saya tidak begitu yakin tapi iirc ada perbedaan antara mengutip pola di dalam 'dan ". Afaik dalam pola yang diapit oleh' urutan pelolosan ditafsirkan sebagai string yang tepat sehingga '\ r' akan setara dengan" \\ r "dan" \ r "tidak memiliki padanan (setidaknya dalam notasi itu) dengan '.
Anticom

Anticom: Anda benar dalam hal ini bahwa perbedaan antara 'dan "tidak relevan; namun, umumnya keduanya berbeda karena' string yang dikelilingi kutipan lemah, dan" dikutip kuat. Hal terbesar yang saya manfaatkan adalah $ expansions atau `` jangan berkembang dalam string yang dikutip dengan lemah. Lihat bash-hackers tentang mengutip untuk informasi lebih lanjut.
bschlueter

4
Cara termudah adalah menggunakan modern dos2unixdengan -icsakelar. Untuk file LF Anda dapat mencari dengan unix2dos -ic. Itu tidak mengubah file. Hanya laporkan.
gavenkoa

3
karena ini adalah jawaban teratas untuk pertanyaan apa pun mengenai akhiran baris Windows / pengembalian kereta di Linux, saya pikir perlu dicatat bahwa Anda dapat melihatnya di terminal dengan perintah cat -v somefile.txt; mereka muncul sebagai^M
user5359531

Jawaban:


121

Gunakan Ctrl+ V, Ctrl+ Muntuk memasukkan karakter Carriage Return literal ke dalam string grep Anda. Begitu:

grep -IUr --color "^M"

akan berfungsi - jika ^Mada CR literal yang Anda masukkan seperti yang saya sarankan.

Jika Anda menginginkan daftar file, Anda juga ingin menambahkan -lopsi.

Penjelasan

  • -I abaikan file biner
  • -Umencegah grep untuk menghapus karakter CR. Secara default itu akan melakukannya jika memutuskan itu adalah file teks.
  • -r membaca semua file di bawah setiap direktori secara rekursif.

3
Sebagai peretasan cepat yang akan berhasil tetapi saya pikir solusi readbale manusia adalah: grep $ '\ r' / bash shell only / atau grepprintf '\r'
akostadinov

5
@akostadinov +1, Tapi backticks ditafsirkan dari komentar Anda;) Opsi kedua, dengan kata lain, adalah grep $(printf '\r'). Tetapi untuk sebagian besar penggunaan praktis yang melibatkan bash, saya akan tetap menggunakannya $'\r'.
jankes

3
Catatan: Opsi -Uini hanya relevan untuk Windows (atau cygwin), tetapi sangat penting di sana. Di Windows, perintah tidak akan berfungsi tanpanya.
sleske

3
Apa gunanya pilihan -I? Secara manual, menurut saya file biner dianggap tidak cocok. Bukankah kombinasi dari -Idan -U(yang memberlakukan tipe biner) mengakibatkan semua file dianggap tidak cocok?
Jānis Elmeris

3
Anda menyebutkan tanda '-l' sebagai opsi tambahan, tetapi saya pikir itu harus dimasukkan dalam jawaban utama karena pertanyaannya pada dasarnya menanyakan daftar file. Selain itu, ini menghasilkan pencarian yang lebih cepat.
arr_sea

168

grep mungkin bukan alat yang Anda inginkan untuk ini. Ini akan mencetak baris untuk setiap baris yang cocok di setiap file. Kecuali Anda ingin, katakanlah, menjalankan todos 10 kali pada file 10 baris, grep bukanlah cara terbaik untuk melakukannya. Menggunakan find untuk menjalankan file pada setiap file di pohon kemudian melakukan grep melalui itu untuk "CRLF" akan memberi Anda satu baris output untuk setiap file yang memiliki akhiran baris gaya dos:

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

akan memberi Anda sesuatu seperti:

./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

Aku sudah memecahkan ini, tapi terima kasih. grep -IUrl --color '^M' . | xargs -ifile fromdos 'file'
Tim Abell

5
Opsi -l untuk grep memberi tahu itu untuk hanya mencantumkan file (sekali) alih-alih mencantumkan kecocokan di setiap file.
pjz

8
Bukan solusi yang baik, untuk bergantung pada perilaku fileprogram (tidak berdokumen, berorientasi pada konsumsi manusia) . Ini sangat rapuh. Untuk (hanya satu) contoh: ini tidak berfungsi dengan file XML, filelaporan XML document textterlepas dari jenis baris baru.
leonbloy

1
@leonbloy, opsi tampaknya menjadi huruf kecil -m /dev/nulldi saya find (GNU findutils) 4.4.2(Ubuntu 12.04).
EarlCrapstone

8
Saya paling suka jawaban ini. Saya hanya melakukannyafind . -type f | xargs file | grep CRLF
Brianz

58

11
Terima kasih! Untuk kejelasan bagi mereka yang datang setelahnya, manual bash mengatakan "Kata-kata dalam bentuk $ 'string' diperlakukan secara khusus. Kata tersebut diperluas menjadi string, dengan karakter yang diloloskan dengan garis miring terbalik diganti seperti yang ditentukan oleh standar ANSI C." (lihat juga daftar kode yang didukung ini )
Sean Gugler

5
Jadi, apakah pesta ini khusus? Harus diperhatikan jika ya.
cubuspl42

untuk git dengan autocrlf yang buruk, saya akan menggunakan: grep -IUlrZ $ '\ r' | xargs -0 sed -zbi 's / \ r // g'
buzard

16

Jika versi grep Anda mendukung opsi -P (--perl-regexp) , maka

grep -lUP '\r$'

bisa digunakan.


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

Kueri adalah mencari ... Saya memiliki masalah yang sama ... seseorang mengirimkan akhiran baris campuran ke kontrol versi, jadi sekarang kami memiliki banyak file dengan 0x0d 0x0d 0x0aakhiran baris. Catat itu

grep -P '\x0d\x0a'

menemukan semua baris, sedangkan

grep -P '\x0d\x0d\x0a'

dan

grep -P '\x0d\x0d'

tidak menemukan baris sehingga mungkin ada sesuatu "lain" yang terjadi di dalam grep ketika berhubungan dengan pola akhir baris ... sayangnya bagi saya!


3

Anda dapat menggunakan perintah file di unix. Ini memberi Anda pengkodean karakter file bersama dengan terminator baris.

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

1

Jika, seperti saya, unix minimalis Anda tidak menyertakan keramahan seperti perintah file , dan garis miring terbalik dalam ekspresi grep Anda tidak bekerja sama, coba ini:

$ 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

Modifikasi yang mungkin ingin Anda lakukan di atas meliputi:

  • ubah perintah find untuk mencari file yang ingin Anda pindai saja
  • ubah perintah dump ke od atau utilitas dump file apa pun yang Anda miliki
  • konfirmasi bahwa perintah cut menyertakan spasi di depan dan di belakang serta hanya keluaran karakter heksadesimal dari utilitas dump
  • batasi keluaran dump hingga 1000 karakter pertama atau lebih untuk efisiensi

Misalnya, sesuatu seperti ini mungkin berhasil untuk Anda menggunakan od, bukan dump :

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

1

dos2unix memiliki opsi informasi file yang dapat digunakan untuk menampilkan file yang akan dikonversi:

dos2unix -ic /path/to/file

Untuk melakukan itu secara rekursif Anda dapat menggunakan bash's globstarpilihan, yang untuk shell saat diaktifkan dengan shopt -s globstar:

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

Atau Anda dapat menggunakan finduntuk itu:

find -exec dos2unix -ic {} +            # all files recursively
find -name file -exec dos2unix -ic {} + # files called “file” recursively
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.