Both will be able to execute commands in container. Both could detach the container.
So what is the real difference between docker exec and docker attach?
As Michael Sun stated in his answer
docker execexecutes a new command / create a new process in the container’s environment, whiledocker attachjust connects the standard input/output/error of the main process(with PID 1) inside the container to corresponding standard input/output/error of current terminal(the terminal you are using to run the command).
My answer will focus more on letting you validate the above statement and understand it more clearly.
Open up a terminal window and run the command docker run -itd --name busybox busybox /bin/sh. The command will pull the image busybox if not already present. It will then create a container with the name busybox using this image.
You can check the status of your container by running the command docker ps -a | grep busybox.
If you run docker top busybox, you should see an output something like this.
UID PID PPID C STIME TTY TIME CMD
root 7469 7451 0 11:40 pts/0 00:00:00 /bin/sh
Of course, the PID, PPID and other values will be different in your case. You can use other tools and utilities as well like pstree, top, htop to see the list of PID and PPID.
The PID and PPID means the process id and parent process id. The process started when we created and started our container with the command /bin/sh. Now, run the command docker attach busybox. This will attach the standard input/output/error stream of the container to your terminal.
After attaching the container, create a shell session by running the command sh. Press CTRL-p CTRL-q sequence. This will detach the terminal from the container and will keep the container running. If you'll now run docker top busybox, you should see two processes in the list.
UID PID PPID C STIME TTY TIME CMD
root 7469 7451 0 11:40 pts/0 00:00:00 /bin/sh
root 7737 7469 0 11:43 pts/0 00:00:00 sh
But the PPID of the two processes will be different. In fact, the PPID of the second process will be the same as PID of the first one. The first process acts as the parent process for the shell session that we just created.
Now, run docker exec -it busybox sh. Once inside the container, check the list of running processes for the container busybox in another terminal window by running the command docker top busybox. You should see something like this
UID PID PPID C STIME TTY TIME CMD
root 7469 7451 0 11:40 pts/0 00:00:00 /bin/sh
root 7737 7469 0 11:43 pts/0 00:00:00 sh
root 7880 7451 0 11:45 pts/1 00:00:00 sh
The PPID of the first and third process will be the same, which confirms that docker exec creates a new process in the container's environment while docker attach just connects the standard input/output/error of the main process inside the container to corresponding standard input/output/error of current terminal.