Usando ^ fora dos parênteses [...] que significa início da linha. E você cometerá erros quando houver um ponto de escape entre colchetes, [^\.] significa qualquer coisa, exceto barra invertida \ e ponto . , não apenas ponto .
Outra observação de que abcd[^.] não corresponderá a abcd no final da linha.
Então você precisa:
$ grep -E 'abcd([^.]|$)' <file
abcd
defgh. abcd
abcd .defgh