disponible aussi en Français.
A few weeks ago, a badly initialized locale sent me digging inside an ECS task in staging. That produced an article on iconv and a guide to ECS Exec (in French). Later, a PrestaShop back office became unreachable and I had to go through ECS Exec again, this time in production, to check the instanceâs actual configuration, the running processes and how long they had been running (that incident is written up here). The right fix there was to run a cache command directly on the instance. The script Iâm describing here didnât exist yet, and it played no part in the diagnosis or the fix. It came afterwards.
The sequence
Both times, I had to reread my own documentation before I could open the shell. To start a session with ECS Exec, you need the cluster, the service, the task ID and the container name. Thatâs four aws ecs ... commands in a row, each one fed with a value copied from the previous output. The guide covers all of this, so I wonât go over it again.
You donât get onto an instance often, and itâs better if it stays that way. So every time, Iâve forgotten the exact sequence. It usually happens when youâre in a hurry, with your head already full of the problem. In production, juggling aws commands you no longer know by heart adds stress you could do without. On top of that, a task ID changes with every deployment, so no command can be replayed as is from one time to the next.
So I wrote aws-ecs-shell, a Bash script of about 250 lines, written with the help of AI like pretty much everything I do these days.
What it looks like
With no arguments, the script shows numbered menus: clusters, then services, then running tasks, then containers.
$ ./aws-ecs-shell.sh
1) alpha
2) beta
Cluster (number, Ctrl-D to cancel) > 2
Service: web
1) 7f3c0e1a9b⊠(started 2026-10-09T10:00:00Z)
2) c41d88b2e0⊠(started 2026-10-08T09:00:00Z)
Task (number, Ctrl-D to cancel) > 1
Container: app
To skip the menus next time: ./aws-ecs-shell.sh --cluster beta --service web --container app
Connecting to ECS task 7f3c0e1a9b⊠(cluster: beta, container: app)...
A menu is skipped when its value is passed as an option (--cluster, --service, --task, --container, --region, --profile) or as an environment variable. A menu with a single entry is picked automatically, which is the most common case for the service and the container.
Three choices I find useful
The replay command. Before connecting, the script prints the command line that skips the menus next time (To skip the menus next time). I donât have to remember the names, I just copy them. The task ID is left out when the service had only one task, since it would be useless after the next deployment. A service with several tasks keeps its ID in the command.
The no-terminal mode. When standard input isnât a terminal (cron, a pipe, another script), there are no menus. The script then requires --cluster, --service or --task, and --container if the task has several, and it lists the available containers in the error message. It never hangs waiting for input.
A single session with a real TTY. The script ends with exec aws ecs execute-command --interactive. That means one persistent SSM session: cd and export carry over from one command to the next, and vim, top and Ctrl-C behave normally.
The shell it starts is bash if the image has it, sh otherwise. execute-command splits --command on spaces and executes the first word without going through a shell, so an if canât be passed as is. The test is base64-encoded and decoded inside the container, with ${IFS} standing in for the spaces so that the whole thing stays a single word. Itâs the same idea as the one in the guide for passing a script, boiled down to one line.
The rest
At startup, the script checks that aws and session-manager-plugin are in the PATH and that the credentials work, then that the task exists and has ECS Exec enabled. Each failure gives a message saying what to fix, rather than a raw API error.
Two details come from the fact that I work on Windows. Under Git Bash, aws.exe ends its lines with a CRLF, and a stray \r in an ARN is enough for ECS to reject it with Unexpected number of separators. The script strips those \r. Itâs also compatible with Bash 3.2, the version that ships with macOS.
The script only reads the ECS API to build its menus and changes nothing on the AWS side. But once youâre in the shell, everything you type runs in the environment you connected to. It doesnât make an intervention any less risky, it just makes it quicker to start.
The code is MIT-licensed: github.com/Shagshag/aws-ecs-shell. The prerequisites (AWS CLI, Session Manager plugin, a task started with enableExecuteCommand, a task role with ssmmessages:*) are in the README.