Jak wyszukiwać pliki zawierające zakończenia wierszy dos (CRLF) za pomocą grep w systemie Linux?

126

Chcę wyszukać pliki zawierające zakończenia wierszy dos za pomocą grep w systemie Linux. Coś takiego:

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

Powyższe wydaje się pasować do dosłownego, rnco nie jest tym, co jest pożądane.

Wynik tego zostanie przesłany potokiem przez xargs do todos, aby przekonwertować crlf na lf w ten sposób

grep -IUrl --color '^M' . | xargs -ifile fromdos 'file'
Tim Abell
źródło
2
Czy próbowałeś dos2unix ? Automatycznie naprawia zakończenia linii.
sblundy
Nie jestem do końca pewien, ale iirc istnieje różnica między cytowaniem wzorca wewnątrz „i”. Afaik we wzorach zawartych w „sekwencje specjalne są interpretowane jako właściwy ciąg, więc„ \ r ”byłoby równoważne z„ \\ r ”i„ \ r "nie ma odpowiednika (przynajmniej w tym zapisie) z '.
Anticom
Anticom: Masz rację w tym przypadku, że różnica między 'a' jest nieistotna, jednak generalnie są one różne, ponieważ 'otoczone ciągi są cytowane słabo, a' są mocno cytowane. Największą rzeczą, z której korzystam, jest to, że rozszerzenia $ lub `` nie rozwijają się w słabo cytowanych łańcuchach. Zobacz bash-hackerów na temat cytowania, aby uzyskać więcej.
bschlueter
4
Najłatwiej jest użyć nowoczesnego dos2unixz -icprzełącznikiem. W przypadku plików LF możesz wyszukiwać za pomocą unix2dos -ic. Nie modyfikuje plików. Tylko raport.
gavenkoa
3
ponieważ jest to najlepsza odpowiedź na każde pytanie dotyczące końcówek linii Windows / powrotu karetki w systemie Linux, myślę, że warto zauważyć, że można je zobaczyć w terminalu za pomocą polecenia cat -v somefile.txt; pojawiają się jako^M
user5359531

Odpowiedzi:

122

Użyj Ctrl+ V, Ctrl+, Maby wprowadzić literalny znak powrotu karetki do łańcucha grep. Więc:

grep -IUr --color "^M"

zadziała - jeśli ^Mistnieje dosłowna CR, którą wprowadzasz, jak sugerowałem.

Jeśli chcesz listę plików, chcesz również dodać tę -lopcję.

Wyjaśnienie

  • -I ignoruj ​​pliki binarne
  • -Uzapobiega usuwaniu przez grep znaków CR. Domyślnie zrobi to, jeśli zdecyduje, że jest to plik tekstowy.
  • -r czyta rekurencyjnie wszystkie pliki w każdym katalogu.
pjz
źródło
3
Jako szybki hack, który by zadziałał, ale myślę, że ludzkim rozwiązaniem readbale byłoby: grep $ '\ r' / bash shell only / lub grepprintf '\r'
akostadinov
5
@akostadinov +1, Ale backticks zostały zinterpretowane z twojego komentarza;) Innymi słowy, druga opcja to grep $(printf '\r'). Ale w przypadku większości praktycznych zastosowań obejmujących bash trzymałbym się $'\r'.
jankes
3
Uwaga: ta opcja -Udotyczy tylko systemu Windows (lub cygwin), ale jest tam krytyczna. W systemie Windows polecenie nie zadziała bez niego.
sleske
3
Jaki jest sens tej opcji -I? Zgodnie z instrukcją wydaje mi się, że pliki binarne są uznawane za niepasujące. Czy kombinacja -Ii -U(która wymusza typ binarny) nie powinna skutkować uznaniem wszystkich plików za niepasujące?
Jānis Elmeris
3
Wspomniałeś o fladze „-l” jako opcji dodatkowej, ale myślę, że powinna ona zostać uwzględniona w podstawowej odpowiedzi, ponieważ pytanie zasadniczo dotyczy listy plików. Ponadto powoduje to szybsze wyszukiwanie.
arr_sea
170

grep prawdopodobnie nie jest narzędziem, którego potrzebujesz do tego. Wypisze linię dla każdej pasującej linii w każdym pliku. Jeśli nie chcesz, powiedzmy, uruchomić todos 10 razy na pliku 10-liniowym, grep nie jest najlepszym sposobem, aby to zrobić. Użycie find, aby uruchomić plik na każdym pliku w drzewie, a następnie przeszukanie tego dla "CRLF" da ci jedną linię wyjścia dla każdego pliku, który ma zakończenia linii w stylu dos:

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

dostaniesz coś takiego:

./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
Thomee
źródło
Już to złamałem, ale i tak dzięki. grep -IUrl --color '^M' . | xargs -ifile fromdos 'file'
Tim Abell,
5
Opcja -l polecenia grep nakazuje mu po prostu wyświetlić listę plików (raz) zamiast wymieniać dopasowania w każdym pliku.
pjz
8
Nie jest to dobre rozwiązanie, poleganie na tym (nieudokumentowanym, zorientowanym na spożycie przez ludzi) zachowaniu fileprogramu. To jest bardzo delikatne. Na (tylko jeden) przykład: nie działa z plikami XML, fileraportami XML document textniezależnie od typu nowych linii.
leonbloy
1
@leonbloy, opcja wygląda na małą literę -m /dev/nullna moim find (GNU findutils) 4.4.2(Ubuntu 12.04).
EarlCrapstone,
8
Najbardziej podoba mi się ta odpowiedź. Po prostu to zrobiłemfind . -type f | xargs file | grep CRLF
brianz
58
grep -IUlr $'\r'

wyjaśniahell.com - grep -IUlr

Steven Penny
źródło
11
Dzięki! Dla jasności tych, którzy przyjdą później, w podręczniku bash napisano, że „Słowa w postaci $ 'string' są traktowane specjalnie. Słowo rozwija się do łańcucha, a znaki ze znakiem ucieczki odwrotnym ukośnikiem są zastępowane zgodnie ze standardem ANSI C.”. (zobacz także listę obsługiwanych kodów )
Sean Gugler,
5
Czy to jest specyficzne dla basha? Należy zauważyć, czy tak jest.
cubuspl42
dla gita ze złym autocrlf użyłbym: grep -IUlrZ $ '\ r' | xargs -0 sed -zbi 's / \ r // g'
buzard
17

Jeśli twoja wersja grep obsługuje opcję -P (--perl-regexp) , to

grep -lUP '\r$'

może być użyty.

Linulin
źródło
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
yabt
źródło
3

Zapytaniem było wyszukiwanie ... Mam podobny problem ... Ktoś przesłał mieszane zakończenia wierszy do kontroli wersji, więc teraz mamy kilka plików z 0x0d 0x0d 0x0azakończeniami wierszy. Zwróć na to uwagę

grep -P '\x0d\x0a'

znajduje wszystkie wiersze, podczas gdy

grep -P '\x0d\x0d\x0a'

i

grep -P '\x0d\x0d'

nie znajduje linii, więc może być coś „innego” w grep, jeśli chodzi o wzorce zakończenia linii ... niestety dla mnie!

Peter Y
źródło
3

Możesz użyć polecenia pliku w systemie unix. Zapewnia kodowanie znaków pliku wraz z terminatorami linii.

$ file myfile
myfile: ISO-8859 text, with CRLF line terminators
$ file myfile | grep -ow CRLF
CRLF  
Murali Krishna Parimi
źródło
1

Jeśli, tak jak ja, twój minimalistyczny unix nie zawiera subtelności, takich jak polecenie pliku , a ukośniki odwrotne w wyrażeniach grep po prostu nie współpracują, spróbuj tego:

$ 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

Modyfikacje, które możesz chcieć wprowadzić w powyższym, obejmują:

  • zmodyfikuj polecenie find, aby zlokalizować tylko pliki, które chcesz przeskanować
  • zmień polecenie dump na od lub inne narzędzie do zrzutu plików, które posiadasz
  • potwierdź, że polecenie cut zawiera spację wiodącą i końcową, a także tylko szesnastkowy znak wyjściowy ze zrzutu narzędzia
  • ogranicz wyjście zrzutu do pierwszych 1000 znaków lub więcej dla wydajności

Na przykład coś takiego może zadziałać, używając od zamiast dump :

 od -t x2 -N 1000 $file | cut -c8- | egrep -m1 -q ' 0d| 0d|0d$'
MykennaC
źródło
1

dos2unix ma opcję informacji o pliku, której można użyć do wyświetlenia plików, które zostaną przekonwertowane:

dos2unix -ic /path/to/file

Aby zrobić to rekursywnie można użyć bash„s globstaropcję, która dla bieżącej powłoki jest włączona shopt -s globstar:

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

Alternatywnie możesz użyć finddo tego:

find -exec dos2unix -ic {} +            # all files recursively
find -name file -exec dos2unix -ic {} + # files called “file” recursively
deser
źródło