AWS S3 How to check if a file exists in a bucket using bash
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
If you need to check whether an object exists in Amazon S3 from Bash, use the AWS CLI command that was built for object metadata rather than parsing directory-style output. The most reliable pattern is aws s3api head-object, because it gives you a clear exit status that works naturally in shell scripts.
Use head-object for Exact Object Checks
head-object asks S3 for metadata about one exact key. If the object exists and your credentials are allowed to inspect it, the command exits successfully.
In a script, the exit code is more useful than the JSON response. That means the cleanest existence check is usually just an if statement:
This approach is better than parsing aws s3 ls output because it is explicit, machine-friendly, and less fragile when filenames contain spaces or when the command prints warnings.
Wrap the Logic in a Reusable Function
A shell function keeps deployment scripts readable and makes it easier to handle multiple checks consistently.
Because the function returns the CLI exit status, it behaves like any other Bash test command.
Understand What Failure Means
The main trap is assuming every failure means "object does not exist". A failed head-object can also mean:
- the bucket name is wrong
- the key is wrong
- the active profile points to the wrong account
- the request is sent to the wrong region
- the caller lacks S3 permissions
When you need to distinguish those cases, capture the error message instead of discarding it.
That is especially useful in CI pipelines, where a permission regression can look identical to a missing build artifact if you only read the boolean result.
When a Prefix Search Is Better
If you are not checking one exact key, head-object is the wrong tool. For prefix-style checks such as "does anything exist under this path", use list-objects-v2.
That solves a different problem. head-object is for an exact key. list-objects-v2 is for discovery under a prefix.
Verify Your AWS Context Early
Many S3 Bash bugs are really credential bugs. Before rewriting the script, confirm which identity and profile are active.
If you use named profiles, include the profile explicitly in the same script that performs the check. If you depend on environment variables such as AWS_PROFILE or AWS_REGION, log them when troubleshooting. Silent context drift is common in local development, CI, and cron jobs.
Why aws s3 ls Is Usually the Wrong Interface
People often write:
This can work interactively, but it is weaker in automation because:
- the output format is made for humans
- distinguishing empty output from an error is awkward
- parsing becomes brittle if you expand the script later
For scripts, prefer the s3api commands because they map more directly to the underlying API and have more predictable return behavior.
Common Pitfalls
- Parsing
aws s3 lsoutput instead of checking thehead-objectexit code. - Treating all failures as object-not-found instead of also checking identity, region, and permissions.
- Forgetting to quote bucket and key variables in Bash.
- Using
list-objects-v2for an exact-object check whenhead-objectis simpler. - Debugging shell syntax first when the active AWS profile is actually wrong.
Summary
- Use
aws s3api head-objectfor exact S3 object existence checks in Bash. - Check the exit status rather than parsing CLI output.
- Capture stderr when you need to tell missing objects apart from access or region problems.
- Use
list-objects-v2only when you are testing a prefix, not a single key. - Verify your AWS identity and profile early when the result looks suspicious.

