01Shell basics

A shell reads what you type, expands it, and runs it. Know these and the rest follows.

echo $SHELL                  # which shell you're running (e.g. /bin/bash)
type -a ls                   # is it a builtin, alias, or program? show all
which python3                # full path of an executable in $PATH
'literal $HOME'              # single quotes: no expansion (prints $HOME)
"expanded $HOME"             # double quotes: variables expand
echo file_*.log              # globbing: * ? [abc] match filenames
cmd1; cmd2                   # run in sequence; cmd1 && cmd2 = only if first ok
!!                           # repeat the last command (sudo !! is handy)
!$                           # last argument of the previous command
man ss   # or: ss --help      # the manual / usage — first stop for any flag
$ type -a ls
ls is aliased to `ls --color=auto'
ls is /usr/bin/ls

02Environment variables — manipulate them

A variable is a name holding a value. Export it and child processes inherit it — that's how you configure most CLIs.

exported variable = name + value + export

NAME=alban                   # shell variable (this shell only)
export NAME                   # promote it to an environment variable
export EDITOR=vim             # set + export in one line
echo "$NAME"                 # read it (quote to be safe with spaces)
printenv PATH                # print one environment variable
env | sort | less            # list the whole environment
AWS_PROFILE=prod aws s3 ls   # one-shot: set a var for a single command only
: "${REGION:=eu-central-1}"  # default a var if unset (parameter expansion)
echo "${NAME:-guest}"        # use a fallback without assigning
unset NAME                   # remove a variable
export PATH="$HOME/bin:$PATH" # prepend a dir to PATH (order = priority)
$ printenv PATH
/home/alban/.local/bin:/usr/local/bin:/usr/bin:/bin

03Make variables persist

Variables vanish when the shell closes. Put exports in the right startup file to keep them.

~/.bashrc  /  ~/.zshrc        # per-user, interactive shells (most edits go here)
~/.profile  /  ~/.bash_profile   # per-user, login shells
/etc/environment             # system-wide, all users (KEY=value, no 'export')
source ~/.bashrc             # reload without logging out (or: . ~/.bashrc)
# Example line to add to ~/.bashrc:
export PATH="$HOME/.local/bin:$PATH"

04Handling secrets safely — best practices

Environment variables are inherited by every child process and are readable via ps e and /proc/<pid>/environ, so a secret in your environment is not really hidden. Treat credentials with care — set this up before touching the cloud CLIs below.

  • Never hardcode or commit secrets. Gitignore .env, ~/.aws/credentials, and *.pem; scan for leaks with gitleaks or git-secrets in a pre-commit hook.
  • Use the tool's own credential store, not raw keys — aws configure / aws configure sso, and az login or a managed identity. Lock file permissions.
  • Prefer short-lived credentials — STS assume-role, or OIDC federation in CI — over long-lived static keys.
  • Use a secret manager / vault — AWS Secrets Manager, Azure Key Vault, or HashiCorp Vault — and fetch at runtime. For local dev, a gitignored .env loaded by direnv, or an OS keychain / pass.
  • Keep secrets out of history and listings, rotate them, and grant least privilege.
  • In CI/CD, use the platform's encrypted secrets (e.g. GitHub Actions secrets), never plaintext in the workflow file.
chmod 600 ~/.aws/credentials         # only you can read the credential file
aws configure sso                    # browser-based login, short-lived tokens
export HISTCONTROL=ignorespace       # commands starting with a space skip history
 export TOKEN=...                    #   (note the leading space → not saved)
git secrets --install && git secrets --register-aws   # block AWS keys in commits
gitleaks detect --source .           # scan a repo for committed secrets
direnv allow                         # auto-load a gitignored .env in this dir only
aws sts assume-role \                # get temporary, scoped credentials
  --role-arn arn:aws:iam::123456789012:role/deploy \
  --role-session-name cli
unset AWS_SECRET_ACCESS_KEY          # clear a secret from the environment when done
$ gitleaks detect --source .
9:14AM INF scanned ~128 commits
9:14AM INF no leaks found

05Networking on the CLI

Most CLIs and package managers obey the proxy environment variables — essential behind a corporate egress. For the full networking toolkit, see the Linux commands guide.

export http_proxy=http://proxy.example.com:8080    # HTTP via a proxy
export https_proxy=http://proxy.example.com:8080   # HTTPS via a proxy
export no_proxy=localhost,127.0.0.1,10.0.0.0/8     # bypass the proxy for these
curl -I https://example.com          # check reachability + headers (obeys *_proxy)
curl -x http://proxy.example.com:8080 https://example.com   # one-off explicit proxy
ip -br a                             # local interfaces + addresses (quick view)
ss -tulpn                            # listening TCP/UDP ports + owning PIDs
dig +short A example.com             # resolve a name (is DNS the problem?)
$ curl -I https://example.com
HTTP/2 200
content-type: text/html; charset=UTF-8
server: nginx

06AWS on the CLI (aws)

Configure once, switch contexts with a profile and region, and confirm who you are before you run anything that changes state.

AWS static credentials = access key ID + secret access key (+ session token)

aws configure                        # interactive: writes ~/.aws/{config,credentials}
aws configure sso                    # preferred: SSO login, temporary credentials
export AWS_PROFILE=prod              # pick a named profile for this shell
export AWS_REGION=eu-central-1       # region (AWS_DEFAULT_REGION also works)
# Static keys are a last resort — placeholders below are AWS's public examples:
export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
export AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
aws sts get-caller-identity          # who am I? (account + ARN) — always verify first
aws s3 ls                            # list buckets
aws ec2 describe-instances \         # servers, as a table
  --query 'Reservations[].Instances[].[InstanceId,State.Name,PrivateIpAddress]' \
  --output table
aws configure list-profiles          # what profiles are available
$ aws sts get-caller-identity
{
    "UserId": "AIDAEXAMPLE0PLACEHOLDER",
    "Account": "123456789012",
    "Arn": "arn:aws:iam::123456789012:user/alban"
}

07Azure on the CLI (az)

Log in interactively for day-to-day work; use a service principal's env vars only for automation, and prefer a managed identity where you can.

Azure SP login = tenant ID + client ID + client secret

az login                             # browser sign-in (device code: az login --use-device-code)
az account show                      # current subscription + tenant
az account list -o table             # all subscriptions you can see
az account set --subscription "Prod" # switch active subscription
# Service-principal env vars (automation) — placeholder GUIDs:
export AZURE_TENANT_ID=00000000-0000-0000-0000-000000000000
export AZURE_CLIENT_ID=00000000-0000-0000-0000-000000000000
export AZURE_CLIENT_SECRET=''
export AZURE_SUBSCRIPTION_ID=00000000-0000-0000-0000-000000000000
az group list -o table               # resource groups
az vm list -d -o table               # VMs with power state
az vm list --query "[].{name:name, rg:resourceGroup}" -o table   # shape the output
$ az account show -o table
Name    CloudName    SubscriptionId                        State    IsDefault
------  -----------  ------------------------------------  -------  -----------
Prod    AzureCloud   00000000-0000-0000-0000-000000000000  Enabled  True

08Where to go next

Once these commands are muscle memory, the next step is to stop typing them: wrap the repeatable ones in scripts, feed credentials from a vault, and let a pipeline run them. That's the jump from a shell session to driving APIs and infrastructure as code. Back to the Knowledge Base.