g | x | w | all
Bytes Lang Time Link
348Python3250331T172844ZAjax1234
256Python 2180410T125158ZDead Pos
249Python 2180410T170143ZChas Bro
171JavaScript ES6180410T131110ZArnauld

Python3, 348 bytes

E=enumerate
def f(b,n):
 d={(x,y):v for x,r in E(b)for y,v in E(r)}
 q=[(*i,[i],n,b)for i in d if'@'==d[i]]
 for x,y,p,n,B in q:
  if'$'==d[(x,y)]:
   if 0==n:return B
   continue
  for X,Y,K in[(1,0,'v'),(0,1,'>'),(-1,0,'^'),(0,-1,'<')]:
   if d.get(N:=(x+X,y+Y))in['$',' ']and n and N not in p:U=eval(str(B));U[N[0]][N[1]]=K;q+=[(*N,p+[N],n-1,U)]

Try it online!

Python 2, 310 256 bytes

Thanks @cairdcoinheringaahing for except:0 -3 bytes
Thanks @Mnemonic for -8 bytes
Thanks @JonathanAllan for -3 bytes
Thanks @ovs for -5 bytes

G,L=input()
R=[]
def S(x,y,G,c,R):
 try:
	if x>-1<y<G[y][x]in' @':i=0;exec"T=[r[:]for r in G];T[y][x]='<v^>'[i];S(x+~-i/2,y+~-(i^2)/2,T,c-1,R);i+=1;"*4
	R+=[G]*(0==c<'$'==G[y][x])
 except:0
for i,y in enumerate(G):"@"in y>S(y.index("@"),i,G,L,R)
print R[0]

Try it online!

Some explanation:

try-except is used to ensure, that both x and y coordinates are in boundaries. Exception will be raised upon access to G[y][x]. Python is too good and negative indices are acceptable, so check x>-1<y is added.

T=[r[:]for r in G] used to create copy of G by values

~-i/2 and ~-(i^2)/2 are used to generate pairs (-1, 0), (0, 1), (0, -1), (1, 0), that used to move in grid (there still should be shorter way!)

R+=[G]*(0==c<'$'==G[y][x]) check, that '$' is reached in required number of steps. R is used to get this result from recursive function calls.

for i,y in enumerate(G):"@"in y>S(y.index("@"),i,G,L,R) Found x and y of '@' in input and call function S.

print R[0] R might contain more that one solution, so output just first

Python 2, 264 261 251 249 bytes

def f(a,n,r=-1,s=0):
 j=len(a[0]);x=1;z=y=0
 if r<0:s,r=divmod(sum(a,[]).index('@'),j)
 for c in'>v<^':
	u=r+x;v=s+y;x,y=-y,x
	if j>u>-1<v<len(a):b=[e[:]for e in a];b[s][r]=c;w=a[v][u];z=n*(w<'!')and f(b,n-1,u,v)or n==1and w=='$'and b
	if z:return z

Try it online!

JavaScript (ES6), 171 bytes

Takes input in currying syntax (a)(n). Outputs by modifying the input matrix.

a=>g=(n,y=a[F='findIndex'](r=>~(i=r[F](v=>v>'?'))),x=i,R=a[y])=>!n--|[-1,0,1,2].every(d=>(R[x]='<^>v'[d+1],(c=(a[Y=y+~-d%2]||0)[X=x+d%2])<1?g(n,Y,X):n|c!='$')&&(R[x]=' '))

Try it online!

Commented

a =>                           // a[] = input matrix
g = (                          // g = recursive function taking:
  n,                           //   n = number of remaining moves
                               //   (x, y) = current coordinates, initialized as follows:
  y = a[F = 'findIndex'](r =>  //     y = index of the row containing the starting point,
    ~(i = r[F](v => v > '?'))  //         found by iterating over all rows r until we
  ),                           //         find some i such that r[i] > '?'
  x = i,                       //     x = index of the column of the starting point
  R = a[y]                     //   R[] = current row
) =>                           //
  !n-- |                       // decrement n; force failure if we're out of moves
  [-1, 0, 1, 2].every(d =>     // for each direction d, where -1 = left, 0 = up,
    (                          // 1 = right and 2 = down:
      R[x] = '<^>v'[d + 1], (  //   update the current cell with the direction symbol
        c = (                  //   c = content of the new cell at (X, Y) with:
          a[Y = y + ~-d % 2]   //     Y = y + dy
          || 0                 //     (use a dummy value if this row does not exist)
        )[X = x + d % 2]       //     X = x + dx
      ) < 1 ?                  //   if c is a space:
        g(n, Y, X)             //     we can go on with a recursive call
      :                        //   else:
        n | c != '$'           //     return false if n = 0 and we've reached the target
    ) &&                       //   unless the above result is falsy,
    (R[x] = ' ')               //   restore the current cell to a space
  )                            // end of every()