Ваша проблема не имеет ничего общего с вашей заменой;когда вы присваиваете строку в первую очередь:
$str = "abc#$and@def";
$and
и @def
обрабатываются как переменные для интерполяции.
Вам необходимо экранировать символы или использовать одиночныекавычки (которые не интерполируют переменные):
$str = 'abc#$and@def';
# or
$str = "abc#\$and\@def";
И вам действительно нужно включить предупреждения, которые сказали бы, что ваше назначение было проблемой.