Ao escrever scripts, se você tiver um erro, precisará echo de suas variáveis para entender o que está acontecendo. Este é o primeiro passo na depuração. Se você tivesse feito isso, você teria visto que o comando grep não está sendo executado e, em vez disso, está sendo salvo como $i :
$ for i in 'grep -l matchpattern $firstdir/*'; do
echo "i is: $i";
done
i is: grep -l matchpattern $firstdir/*
Para passar os resultados de um comando, você precisa usar substituição de comando . Isso é 'command' ou, melhor, $(command) . Então, o que você queria fazer era:
for i in $(grep -l matchpattern "$firstdir"/*); do
mv "$i" "$seconddir"
done