⚖️ Four Cloud CLIs Side by Side: az, aws, gcloud and oci
The same job in four command-line tools: signing in, finding out where you are, defaults, output, queries (with a JMESPath primer), help, and cleaning up
💡 How this page was made. It collects what the four CLI pages found, so it inherits their method: the offline parts (versions, errors, config files, help, queries on built-in data) were run for real on 6 October 2026 with az 2.91.0, aws-cli 2.37.9, gcloud 588.0.0 and oci 3.94.2, in throwaway folders with empty home directories. Anything that needs a signed-in account is from the documentation, not run here. The detail is on the pages for az, aws, gcloud and oci.
The shape of a command
- az: az GROUP SUBCOMMAND --option. Example: az vm list.
- aws: aws SERVICE OPERATION --option. Example: aws ec2 describe-instances.
- gcloud: gcloud GROUP [SUBGROUP] VERB --flag. Example: gcloud compute instances list.
- oci: oci SERVICE RESOURCE ACTION --option. Example: oci compute instance list.
The version command is the same everywhere in spirit: az --version, aws --version, gcloud --version, oci --version.
What each says when you are not signed in
All four were run unsigned. The wording (real) tells you which tool you are looking at:
- az: ERROR: Please run 'az login' to setup account.
- aws: An error occurred (NoCredentials): Unable to locate credentials. You can configure credentials by running "aws login".
- gcloud: ERROR: ... You do not currently have an active account selected. (and gcloud auth list says "No credentialed accounts.")
- oci: ERROR: Could not find config file at ~/.oci/config. Do you want to create a new config file?
Signing in
- az: az login (browser, or --use-device-code). Scripts: service principal or managed identity. MFA is required for user sign-in on the command line.
- aws: aws login, or aws configure sso then aws sso login --profile P. Roles on machines. Long-lived access keys are the last resort.
- gcloud: gcloud init or gcloud auth login. For your own programs: gcloud auth application-default login. Service account keys are discouraged.
- oci: oci setup config (an API signing key and three OCIDs), or oci session authenticate (browser, short-lived), or an instance principal on an Oracle instance.
Without installing anything: Cloud Shell exists on all four clouds, and each one has the CLI ready and signed in.
Where am I?
The most useful habit across all four: ask the tool who and where you are before you change anything.
- az: az account show (and az account list --output table).
- aws: aws sts get-caller-identity (account ID and identity), aws configure list (where each setting came from).
- gcloud: gcloud auth list (the account) and gcloud config list (the project and defaults).
- oci: read ~/.oci/config (the user, tenancy and region of the profile), then oci iam user get --user-id USER_OCID (from the documentation, not run here).
Choosing the account, project or subscription
- az: az account set --subscription NAME.
- aws: a profile: --profile NAME or AWS_PROFILE=NAME (this one was run: the environment variable showed up as TYPE env). Create with aws configure set region R --profile NAME.
- gcloud: a configuration: gcloud config configurations create|activate NAME, or --project ID and --configuration NAME per command.
- oci: a profile in ~/.oci/config ([DEFAULT], [LAB]...): --profile NAME.
Defaults for region, location, group, project
- az: az config set defaults.location=westeurope defaults.group=lab-rg (file ~/.azure/config). The help of commands then shows "Config: westeurope".
- aws: aws configure set region eu-west-1 (file ~/.aws/config). Environment: AWS_REGION.
- gcloud: gcloud config set project ID, and compute/region, compute/zone. The project works unsigned, but region and zone need a signed-in account.
- oci: region= in the profile. There is no "default compartment" in the config file: pass --compartment-id (keep the OCIDs in shell variables).
Where the settings live: ~/.azure/, ~/.aws/, ~/.config/gcloud/, ~/.oci/. Treat all four folders as secret: they hold tokens or keys.
Output
- az: -o json|jsonc|table|tsv|yaml|yamlc|none.
- aws: --output json|yaml|yaml-stream|text|table. Turn off the pager in scripts: --no-cli-pager.
- gcloud: --format=json|yaml|table(...)|value(...)|csv|text.
- oci: JSON by default, --output table.
For a script, the clean-value forms are: -o tsv (az), --output text (aws), --format="value(...)" (gcloud), and --raw-output or a JMESPath query that returns a single string (oci).
Query: a JMESPath primer
az, aws and oci all use JMESPath in --query. gcloud has its own --format projections and --filter. Learn JMESPath once and it works three times. These examples ran for real on the az cloud list data built into the Azure CLI (no account):
user@lab:~$ az cloud list --output table
IsActive Name Profile
---------- ----------------- ---------
True AzureCloud latest
False AzureChinaCloud latest
False AzureUSGovernment latest
False AzureBleuCloud latest
user@lab:~$ az cloud list --query '[].name' --output tsv
AzureCloud
AzureChinaCloud
AzureUSGovernment
AzureBleuCloud
user@lab:~$ az cloud list --query "[?isActive].{Name:name, ARM:endpoints.resourceManager}" --output json
[
{
"ARM": "https://management.azure.com/",
"Name": "AzureCloud"
}
]
user@lab:~$ az cloud list --query "[].{Name:name, Portal:endpoints.portal}" --output table
Name Portal
----------------- --------------------------------
AzureCloud https://portal.azure.com
AzureChinaCloud https://portal.azure.cn
AzureUSGovernment https://portal.azure.us
AzureBleuCloud https://portal.sovcloud-azure.fr
The building blocks, using those examples:
- [] means "every item of the list", and .name picks a field: [].name.
- [?isActive] is a filter: only the items where the condition holds. With a comparison it reads [?location=='westeurope'] (strings go in single quotes).
- {Name:name, ARM:endpoints.resourceManager} builds a new object with the fields you choose and the names you give them, and endpoints.resourceManager reaches into nested data.
- [0] is the first item, [:5] the first five, [-1] the last.
- Field names are case-sensitive, and names with dashes need double quotes ("display-name").
What differs between the tools is the wrapper around the answer:
- az: the answer is the list itself: --query "[].name".
- aws: the answer is an object with a top-level key named for the content: --query "Regions[].RegionName". Instances are nested: Reservations[].Instances[].
- oci: the answer is wrapped in data: --query "data[*].{id: id}". The CLI also ships canned queries: --query query://list_public_ips (see oci setup oci-cli-rc).
- gcloud: no JMESPath. --filter="status=RUNNING" --format="table(name, zone.basename(), status)".
Shell quoting is the thing that bites: put the query in double quotes and use single quotes inside for strings, or the other way round, and test it on a small command first.
Help, offline
- az: az COMMAND --help. az find "az group create" finds examples (needs the network).
- aws: aws help, aws SERVICE help, aws SERVICE OPERATION help, and aws help topics (try aws help config-vars). --generate-cli-skeleton prints a template of all the options.
- gcloud: gcloud COMMAND --help, and gcloud topic formats and gcloud topic filters.
- oci: oci COMMAND --help, and oci -i for an interactive mode.
The same small jobs in four tools (from the documentation, not run here)
- List the regions. az: az account list-locations --output table. aws: aws ec2 describe-regions --output table. gcloud: gcloud compute regions list. oci: oci iam region list --output table.
- List the virtual machines. az: az vm list --output table. aws: aws ec2 describe-instances --output table. gcloud: gcloud compute instances list. oci: oci compute instance list --compartment-id OCID.
- Make a bucket. aws: aws s3 mb s3://NAME. gcloud: gcloud storage buckets create gs://NAME --location=us-central1. oci: oci os bucket create --compartment-id OCID --name NAME. az: az storage account create ... first (a bucket is a container inside a storage account: see the Azure services map).
- Find the zones. aws: aws ec2 describe-availability-zones. gcloud: gcloud compute zones list. az: az account list-locations --query "[?availabilityZoneMappings]". oci: oci iam availability-domain list --compartment-id OCID.
Cleaning up
- az: az group delete --name X --yes --no-wait: a resource group deletes everything in it.
- gcloud: gcloud projects delete ID: the project is the unit (30 days to restore).
- aws: there is no group: delete each resource, or use a CloudFormation stack, and look in every region (EC2 Global View).
- oci: delete or terminate the resources, and keep experiments in a compartment of their own so you can list what is left.
The mistakes that are the same everywhere
- Wrong account, subscription, project or profile. Fix: the "where am I" command above, every time.
- Wrong region. The default is in the profile or configuration, and a forgotten one puts things somewhere unexpected.
- Secrets in the wrong place: keys in repositories, tokens in shell history, config folders in backups.
- Long-lived keys instead of short-lived sign-in.
- Quotes. A query that works in one shell breaks in another.
- Running a delete without listing first. List with the same filter, then delete.
The cheat sheet
- Who am I: az account show | aws sts get-caller-identity | gcloud auth list + gcloud config list | ~/.oci/config.
- Sign in: az login | aws login or aws configure sso | gcloud auth login | oci setup config or oci session authenticate.
- Switch: az account set | --profile / AWS_PROFILE | gcloud config configurations activate | --profile.
- Output: -o table | --output table | --format=table(...) | --output table.
- Query: JMESPath on az, aws and oci (wrappers: none, top-level key, data). gcloud: --format and --filter.
- Help: --help everywhere; aws help topics; gcloud topic formats; oci -i.
- Clean up: az group delete | resources and stacks | gcloud projects delete | a compartment per experiment.
← The Oracle Cloud CLI (oci): Config File, API Keys, Sessions and Query · ↑ All tutorials