Study guide

5.3 Shells, Variables, and the Environment

Kali Linux Certified Professional KLCP

Track your progress as you read

Finished sections get a check mark.

1 Introduction & Exam Overview

1.1 Current Exam Facts 1.2 How to Use This Guide & Study Strategy 1.3 PEN-103 Syllabus & Study Path

2 About Kali Linux

2.1 A Bit of History: From BackTrack to Kali 2.2 Kali's Relationship with Debian 2.3 Purpose and Use Cases 2.4 Main Features and Design Policies

3 Getting Started with Kali Linux

3.1 Downloading and Verifying a Kali ISO 3.2 Booting Kali in Live Mode 3.3 Installation Options Overview 3.4 Troubleshooting Installations

4 Linux Fundamentals

4.1 What Linux Is and What It Does 4.2 The Command Line 4.3 The Filesystem Hierarchy Standard 4.4 Useful Commands: Files, Search, Environment

5 Permissions and Process Management

5.1 File Permissions and Ownership 5.2 Managing Processes 5.3 Shells, Variables, and the Environment

6 Installing Kali Linux

6.1 Minimal Installation Requirements 6.2 Step-by-Step Installation on a Hard Drive 6.3 Unattended Installations with Preseeding 6.4 ARM Installations

7 Configuring the Network, Users, and SSH

7.1 Configuring the Network 7.2 Managing Unix Users and Groups 7.3 Configuring SSH

8 Configuring Services

8.1 Apache Web Server 8.2 PostgreSQL Database 8.3 Managing Services with systemd

9 Helping Yourself and Getting Help

9.1 Documentation Sources 9.2 Kali Linux Communities 9.3 Filing Good Bug Reports

10 Security Policy and Network Services

10.1 Defining a Security Policy 10.2 Possible Security Measures 10.3 Securing Network Services

11 Firewalling and Monitoring

11.1 Netfilter and iptables Behavior 11.2 Writing iptables Rules and NAT 11.3 Monitoring and Logging

12 Debian Package Management: APT

12.1 Introduction to APT 12.2 The sources.list File 12.3 Kali Repositories 12.4 Basic Package Interaction with apt

13 dpkg and Advanced Package Management

13.1 dpkg Fundamentals 13.2 Inspecting .deb Files and Package State 13.3 Maintainer Scripts and Conffiles 13.4 APT Pinning and Package Authenticity

14 Advanced Usage

14.1 Modifying and Rebuilding Kali Packages 14.2 Recompiling the Kernel 14.3 Building Custom Kali Live ISO Images 14.4 USB Persistence with LUKS Encryption

15 Kali Linux in the Enterprise

15.1 Network Installation with PXE Boot 15.2 Configuration Management with SaltStack 15.3 Metapackages and Custom Repositories 15.4 Configuration Packages and Forking

16 Introduction to Security Assessments

16.1 Kali Linux in an Assessment 16.2 Types of Assessments 16.3 Types of Attacks 16.4 Formalization and the Road Ahead

5.3 Shells, Variables, and the Environment

Key Takeaways Explain This Topic AI

zsh has been Kali's default interactive shell since 2020.4, but /bin/sh is dash — so #!/bin/sh scripts must be strictly POSIX, not bash-isms.

A user's login shell is set in the seventh (final) field of /etc/passwd, e.g. kali:x:1000:1000:,,,:/home/kali:/usr/bin/zsh.

PATH is a colon-separated search list of directories; echo $PATH inspects it and export PATH="$PATH:/opt/tools" extends it for the session.

export copies a variable into the environment so child processes (subshells, scripts) inherit it; without export, a variable is shell-local.

Login shells read /etc/profile then the user's profile; interactive zsh reads ~/.zshrc — put aliases and PATH tweaks in ~/.zshrc to persist them.

Last updated: July 2026

Which Shell, and Where It Comes From

A shell is the command-line interpreter between you and the kernel. Kali ships several — zsh, bash, dash, sh — and the exam tests their distinct roles. Since Kali 2020.4, zsh is the default interactive shell (previously bash). But look at /bin/sh : ls -l /bin/sh # /bin/sh -> dash

dash (Debian Almquist Shell) is a minimal, fast, strictly POSIX shell used for system scripts. This split is deliberate: humans get zsh's completions and themes, while boot scripts get dash's speed and standards compliance.

Each account's login shell lives in the last field of /etc/passwd : kali:x:1000:1000:Kali,,,:/home/kali:/usr/bin/zsh

Change it with chsh -s /bin/bash (the shell must be listed in /etc/shells ). The running shell's path is in $SHELL (your login shell) while $0 shows what is actually executing right now — they can differ if you launched bash from zsh.

Login vs Non-Login Shells and Startup Files

A login shell starts when you authenticate — console sign-in, SSH, su - , or bash --login . A non-login interactive shell starts when you open a new terminal inside a desktop session or type zsh at a prompt. They read different startup files, and misplacing a setting between them is the classic "my alias works in SSH but not in the terminal" bug:

  • Shell event Files read (in order)
  • zsh login shell /etc/zsh/zprofile , ~/.zprofile , then interactive files
  • zsh interactive (any) /etc/zsh/zshrc , then ~/.zshrc
  • bash login shell /etc/profile , then first of ~/.bash_profile , ~/.bash_login , ~/.profile
  • bash non-login interactive /etc/bash.bashrc , then ~/.bashrc
  • /bin/sh script (dash) none — non-interactive shells read no rc files

Practical rule for Kali's zsh: put export lines, PATH additions, and aliases in ~/.zshrc so every interactive terminal gets them.

Variables and the Environment

The environment is a set of name=value pairs handed to every process at launch. Inspect it with env or printenv ; inspect one variable with echo $PATH . The exam-worthy variables:

PATH — colon-separated directory list the shell searches for commands, e.g. /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin . "Command not found" usually means the binary's directory is not in PATH; which nmap shows what PATH resolves.

HOME — your home directory ( /home/kali ); cd with no arguments goes here.

USER / LOGNAME — the account name.

SHELL — the login shell from /etc/passwd.

LANG — locale, e.g. en_US.UTF-8 , controlling language and sorting.

PS1 — the prompt string.

Shell variables versus environment variables is the key distinction: MYVAR=hello # shell-local: visible only in THIS shell

  • echo $MYVAR # hello
  • bash -c 'echo $MYVAR' # empty — the child did not inherit it
  • export MYVAR=hello # now copied into the environment
  • bash -c 'echo $MYVAR' # hello — children inherit exported vars

A subshell (parentheses ( ... ) , pipelines, command substitution $(...) ) is a child process: it inherits exported variables, but changes it makes — cd , variable assignments — never propagate back to the parent. Extend PATH for the session with export PATH="$PATH:/opt/tools" ; persist it by adding that line to ~/.zshrc .

  • Aliases and Shortcuts
  • An alias substitutes one string for another at the start of a command line: alias ll='ls -alFh'
  • alias grep='grep --color=auto'
  • alias # list all aliases
  • unalias ll # remove one

Aliases are not exported and do not exist inside scripts — they are interactive conveniences defined in ~/.zshrc or ~/.bashrc . For script logic use shell functions instead.

POSIX: Why #!/bin/sh Scripts Must Behave

The shebang ( #! ) on a script's first line selects its interpreter. #!/bin/bash gets bash's full feature set; #!/bin/sh gets dash on Kali, which implements only the POSIX standard. Common bashisms that break under dash:

  • Bashism POSIX-compliant replacement
  • [[ -f file ]] [ -f file ]
  • == inside [ ] =
  • source file.sh . file.sh
  • arrays, declare , local scoping tricks avoid; not in POSIX
  • echo -e printf
  • function name { } name() { }

Test a script's portability with dash -n script.sh (syntax check) or the checkbashisms tool from the devscripts package. The exam angle: a script with #!/bin/sh that works on your bash desktop may fail on Kali or Debian because /bin/sh is dash — always match the shebang to the features you actually use, and when in doubt, write POSIX.

Special Variables, One-Shot Environments, and su

Shells expose built-in special variables that scripts rely on: $? holds the exit status of the last command (0 means success, anything else is an error), $$ is the current shell's PID, $0 the script or shell name, and $# , $1 , $2 ... give the argument count and positional parameters. echo $? immediately after a command is the standard quick success check.

You can also set a variable for a single command without exporting it by prefixing the command: LANG=C sort file.txt runs just that one invocation with the C locale — a common trick for predictable English error messages and sort order. Remove a variable entirely with unset MYVAR .

Be careful with su : plain su switches user but keeps your current environment, while su - (equivalently su -l ) starts a login shell for the target user, reading their profile files and resetting PATH, HOME, and the rest as if they had logged in fresh. Test scripts that depend on PATH under su - or a clean env -i environment. Finally, remember that variable expansion happens in the current shell before the command runs — echo $HOME substitutes locally — which is why single quotes ( echo '$HOME' ) are used to pass a literal $ through to tools like awk that do their own expansion.