O problema era escape de shell . \ é um caractere especial no shell e também em grep .
Em:
grep export_cc\ =\ \$\{dir\}/aaa/bbb/ccc file
export_cc\ =\ \$\{dir\}/aaa/bbb/ccc foi interpretado pelo shell para uma string export_cc = ${dir}/aaa/bbb/ccc antes de passar para grep . Você pode usar o strace para verificar:
$ strace grep export_cc\ =\ \$\{dir\}/aaa/bbb/ccc file
execve("/bin/grep", ["grep", "export_cc = ${dir}/aaa/bbb/ccc",...
Com Substituição de comando :
grep 'printf %q 'export_cc = ${dir}/aaa/bbb/ccc'' file
Sem as aspas duplas, o resultado da substituição de comandos foi split e glob por o shell em três partes: export_cc\ , =\ e \$\{dir\}/aaa/bbb/ccc . O shell tratou-os como três strings, escapando de todas as barras invertidas e passando-os para grep como export_cc\ , =\ , \$\{dir\}/aaa/bbb/ccc :
$ strace grep $(printf %q 'export_cc = ${dir}/aaa/bbb/ccc') file
execve("/bin/grep", ["grep", "export_cc\", "=\", "\$\{dir\}/aaa/bbb/ccc",...
grep recebeu um padrão com uma barra invertida export_cc\ seguido por nada e mostrou a mensagem Trailing backslash .
Para que funcione, você precisa substituir o comando por aspas duplas e usar printf com %s em vez de %q :
$ grep "$(printf %s 'export_cc = ${dir}/aaa/bbb/ccc')" file
export_cc = ${dir}/aaa/bbb/ccc