Reputation: 16184
How can I match a unix line ending with grep? I already have a working script that uses unix2dos
and cmp
, but it's a bit slow, and a single grep command would fit in a lot better with the rest of my bash code.
I tried using a negative lookbehind on '\r'
.
$ printf "foo\r\n" | grep -PUa '(?<!'$'\r'')$'
foo
Why doesn't that work? For the record, the regex pattern seems to evaluate just well this way:
$ printf '(?<!'$'\r'')$' | od -a
0000000 ( ? < ! cr ) $
0000007
Update:
$ grep --version
grep (GNU grep) 2.24
on MINGW64 on windows 7.
Upvotes: 2
Views: 977
Reputation: 32484
Your solution with grep -PUa '(?<!'$'\r'')$'
worked with a more recent version of grep (2.25). However the support for Perl-compatible regular expression (-P
) is stated to be highly experimental even in that newer version of grep, so it's not surprising that it didn't work in the previous version.
Use the following basic regular expression: \([^\r]\|^\)$
, i.e. the following grep
command when running from bash
:
grep -Ua '\([^'$'\r'']\|^\)$'
An example demonstrating that it correctly handles both empty and non-empty lines:
$ printf "foo\nbar\r\n\nx\n\r\ny\nbaz\n" | grep -Ua '\([^'$'\r'']\|^\)$'
foo
x
y
baz
$
EDIT
The solution above treats the last line not including an end-of-line symbol as if it ended with a unix line ending. E.g.
$ printf "foo\nbar" | grep -Ua '\([^'$'\r'']\|^\)$'
foo
bar
That can be fixed by appending an artificial CRLF to the input - if the input ends with a newline, then the extra (empty) line will be dropped by grep
, otherwise it will make grep
to drop the last line:
$ { printf "foo\nbar"; printf "\r\n"; } | grep -Ua '\([^'$'\r'']\|^\)$'
foo
$
Upvotes: 3