انتقل إلى المحتوى
أمين أبوزيد
منشورBEG-005-L03

متغيرات البيئة وPATH

  • الدرس 3 من 6
  • 16 دقيقة قراءة
  • مبتدئ
في هذا الدرس 11 موضوعات

هذا الدرس متاح حاليًا باللغة الإنجليزية فقط، ولم تُنشر نسخته العربية بعد.

Lesson Overview

In the last lesson you typed java -version and the terminal answered. You never told it where the java program lives. How did it know? The answer is an environment variable called PATH, and understanding it is the single most useful skill in this module. When it is missing or wrong, you get the famous message "command not found", which stops thousands of beginners every year.

Keep the workshop picture in mind. The JDK is a set of tools on the bench. PATH is the list that says which shelves to look on when you ask for a tool by name. If the shelf that holds java is not on the list, the tool is in the workshop but nobody can find it.

This lesson teaches what an environment variable is, how PATH works, how to print it on each system, how to read a "command not found" error, how to repair it temporarily and permanently, and what JAVA_HOME is for. It ends with the habit that solves a surprising share of problems: after a change, test in a new terminal.

Exact menus differ between Windows versions, and shells differ between systems. The lesson gives the typical route and tells you where to check your own system's documentation. Be careful when you change system settings. Everything here can be undone, but write down the old value before you edit anything.

Learning Objectives

By the end of this lesson you will be able to:

  • Explain what an environment variable is, and give three examples.
  • Explain what PATH is and how the terminal uses it to find a command.
  • Print PATH in Command Prompt, PowerShell, and a Unix shell, and find the JDK folder in it.
  • Read a "command not found" error and list its common causes.
  • Explain why a change to PATH appears only in terminals opened afterwards.
  • Add a folder to PATH for one terminal session, and describe how to make it permanent.
  • Explain what JAVA_HOME holds and how it differs from a PATH entry.

Written Explanation

Environment variables

An environment variable is a named setting that the operating system hands to every program it starts. It has a name and a value, and the value is always text. Examples:

NameTypical meaning
PATHThe list of folders searched for commands
JAVA_HOMEThe folder where the JDK is installed
HOME (macOS and Linux) or USERPROFILE (Windows)Your personal folder
USERNAME or USERYour account name

When one program starts another, the new program receives a copy of its parent's environment at that moment. Microsoft's PowerShell documentation describes the same idea: environment variables are inherited by child processes. The copy is taken at start time. Later changes in the parent do not appear in programs that are already running.

On Windows, variables exist at three levels, according to the same documentation: Machine (also called System), User, and Process. A new process gets a combination of the machine and user values. On macOS and Linux, names are case-sensitive, so PATH and Path would be different variables. On Windows they are not.

PATH: the list of shelves

When you type java -version, the terminal (really, the program called a shell) receives the word java. It has no idea where such a program is. So it consults PATH: a list of folders, which it searches in order, looking in each folder for a program named java. The first match is the one that runs. If no folder holds it, the shell gives up and reports an error.

Microsoft documents the format: PATH holds a list of folders, separated by a semicolon ; on Windows and a colon : on macOS and Linux.

Here is an example of a Windows PATH value (yours will be different):

text
C:\Windows\system32;C:\Windows;C:\Program Files\Java\jdk-<version>\bin

and a Unix-like one:

text
/usr/local/bin:/usr/bin:/bin:/usr/lib/jvm/java-<version>-openjdk/bin

The folder on the end contains java and javac. It is the JDK's bin folder (short for binaries, the programs). The JDK folder itself holds other directories too, and only bin contains the commands, so it is bin that must be on PATH, not the JDK folder one level up.

Because the search is in order, the order matters. If two JDKs are installed and both bin folders are on PATH, the one listed first wins. That is how the second classic mistake arises: the wrong JDK is first.

Printing PATH

ShellCommand to print PATH
Windows Command Promptecho %PATH%
Windows PowerShell$env:PATH
macOS and Linux (Bash, Zsh)echo $PATH

The result is one long line. To make it readable, split it at the separators:

text
PowerShell:   $env:PATH -split ';'
Bash or Zsh:  echo "$PATH" | tr ':' '\n'

You can also ask the shell which program it would run:

ShellCommand
Windows Command Promptwhere java
Windows PowerShellGet-Command java
macOS and Linuxwhich java

where and which are standard tools on those systems, though I did not verify their exact output formats on an official page. They are the quickest way to see which of several JDKs is being picked.

A program can also read its own environment. This small Java program prints JAVA_HOME and each folder of PATH on its own line. Save it as EnvPeek.java, compile it with javac EnvPeek.java, and run it with java EnvPeek:

java
import java.io.File;

public class EnvPeek {
    public static void main(String[] args) {
        String javaHome = System.getenv("JAVA_HOME");
        System.out.println("JAVA_HOME = " + (javaHome == null ? "(not set)" : javaHome));

        String path = System.getenv("PATH");
        if (path == null) {
            System.out.println("PATH is not set");
            return;
        }
        String[] folders = path.split(File.pathSeparator);
        System.out.println("PATH has " + folders.length + " folders:");
        for (String folder : folders) {
            System.out.println("  " + folder);
        }
    }
}

System.getenv(name) returns the value as a String, or null if the variable does not exist, and File.pathSeparator is ; or : depending on the system. The program runs as a child of your terminal, so it prints what the terminal gave it, which proves the inheritance rule in practice.

"Command not found"

If no folder on PATH holds the command, each shell reports it in its own words. Typical messages:

text
'java' is not recognized as an internal or external command,
operable program or batch file.          (Command Prompt)

The term 'java' is not recognized as the name of a cmdlet, function,
script file, or operable program.        (PowerShell)

bash: java: command not found            (Bash)
zsh: command not found: java             (Zsh)

The wording may differ slightly between versions. The meaning is the same: I searched every folder on PATH and found nothing with that name. The common causes:

  1. Not installed. There is no JDK on the machine.
  2. Installed but not on PATH. The bin folder is not on the list.
  3. Wrong folder on PATH. The entry points to the JDK folder instead of its bin folder, or contains a typo or an outdated version number.
  4. Old terminal. The change was made after the terminal started, so this terminal still has the old copy.
  5. Typing mistake. The command is java, not Java on a case-sensitive system, and not jave.

Work through them in that order, and answer each with a command: where or which, a printed PATH, a look at the folder on disk.

Fixing PATH for one session

The quickest repair affects only the terminal you are in. Replace the folder with your own JDK's bin folder:

text
PowerShell:   $env:PATH = "C:\Program Files\Java\jdk-<version>\bin;" + $env:PATH
Bash or Zsh:  export PATH="/path/to/jdk/bin:$PATH"

The PowerShell documentation confirms that a change made this way affects only the current session. The command puts the JDK folder at the front, so it wins the search. Close the window and the change is gone, which makes this an excellent way to test a fix safely.

Fixing PATH permanently

To keep a change, you edit the stored value that new terminals start from:

  • Windows: The PowerShell documentation describes the route through the System Control Panel: open System, then Advanced System Settings, the Advanced tab, and Environment Variables. You can edit the User list (only you) or the System list (everyone). On newer Windows versions, searching the Start menu for "environment variables" gets you there faster. In the editor, select Path, choose Edit, and add the JDK's bin folder as a new line. Click OK on every dialog, or the change is not saved.
  • macOS and Linux: Add the export PATH=... line to your shell's start-up file. The PowerShell documentation names ~/.bashrc for Bash and ~/.zshrc for Zsh as the usual files for shells started from another shell. Which file your terminal actually reads can depend on whether it is a login shell, so check your system's documentation if the change does not appear. On Linux, a package manager normally sets things up for you, as lesson 2 explained.

After a permanent change, open a new terminal and test. The terminals already open still hold the old copy.

Why a new terminal is needed

This is the rule that explains the third classic mistake. A terminal is a process. It received its environment when it started. Editing the stored PATH afterwards changes what future processes will receive, not what the existing process already has. The existing terminal cannot see the change, and nor can any program started from it. Close it and open a new one, and the new terminal starts with the fresh value. Some IDEs read the environment only when they start, too, so restart the IDE after changing PATH.

JAVA_HOME

JAVA_HOME is a variable whose value is the root folder of the JDK, for example C:\Program Files\Java\jdk-<version> or /usr/lib/jvm/java-<version>-openjdk. It is not the bin folder. Many build tools and servers read JAVA_HOME to find the JDK they should use, so it is common to set it. It is a convention: the java command does not need it to run, while other tools may.

A neat way to avoid repeating yourself is to put JAVA_HOME first and build PATH from it, as in this general pattern from Java setup guides:

text
JAVA_HOME = C:\Program Files\Java\jdk-<version>
PATH      = %JAVA_HOME%\bin;...other folders...

With this setup, changing to a different JDK means changing one variable. I describe this as a common practice, not a requirement, and I did not find it in Oracle's installation overview, which does not discuss the variable.

Examples

Example 1: Finding the JDK folder in PATH (simple)

On Windows PowerShell, Dana runs:

text
$env:PATH -split ';'

The output is a list, one folder per line. She scans it and finds a line ending in \bin that mentions a JDK. That is the shelf where java and javac live. Then she runs Get-Command java, which tells her the exact file the shell would run. The folder printed there matches the line she found. The check takes under a minute and proves that PATH and the real program agree.

Example 2: Fixing "command not found" in one session (practical)

Omar types javac -version in a terminal and gets "command not found", though he is sure he installed a JDK. He investigates:

  1. He lists the JDK folder on disk and finds that the compilers are in .../jdk-<version>/bin.
  2. He prints PATH and does not see that folder.
  3. He adds it for the session: export PATH="/path/to/jdk-<version>/bin:$PATH" (his own path in place of the example).
  4. javac -version now prints a version. The fix works for this terminal only.
  5. To make it permanent, he adds the same export line to his shell's start-up file and opens a new terminal to verify.

The method (find the folder, compare it with PATH, add it, test) is the same on every system.

Example 3: The fix that "does not work" (realistic)

Lena breaks and then repairs her setup on Windows, as the lab requires. She removes the JDK entry from PATH through the Environment Variables dialog, and opens a new Command Prompt. java -version reports "not recognized", which is the expected broken state. She restores the entry in the dialog, clicks OK on all windows, and runs java -version again in the same Command Prompt. It still fails.

She does not conclude that the fix is wrong. She remembers the rule: this window started with the broken copy. She opens another new Command Prompt, and the command works. Two terminals, side by side, show the rule clearly: the old one keeps failing, the new one works, and nothing was reinstalled.

Backend Insight

Environment variables are one of the main ways a backend program is configured on a server. The same program, started with different environment variables, can talk to a test database on your laptop and a real one in production, without changing a line of code. Typical settings passed this way are a database address and a password, or the name of the environment. Secrets such as passwords should come from the environment or a secrets service and never be written into source files that go into version control. Java code reads them with System.getenv, as in the EnvPeek program.

Every server and container starts its programs with an environment, and the inheritance rule you learned here still applies: a program sees what it was given when it started. When a service "ignores" a new setting, the first question is whether it was restarted after the change. The same is true of the build tools and servers that read JAVA_HOME, so a wrong JAVA_HOME is a classic reason for a build to use an unexpected Java version.

The environment differences between a laptop, a build machine, and a server, including different PATH values, are a common source of "works on my machine" problems. A later module returns to this topic. You are learning the debugging method now: print the environment, find which program would run, compare.

Common Mistakes

Mistake 1: Putting the JDK folder, not its bin folder, on PATH

  • Incorrect: C:\Program Files\Java\jdk-<version>
  • Correct: C:\Program Files\Java\jdk-<version>\bin

The commands are inside bin. JAVA_HOME is the one that takes the root folder.

Mistake 2: Several JDKs, and the wrong one is first

The first matching folder wins. If an older JDK is listed before the one you installed, java -version shows the older one. Use where java or which java to see the winner, and move or remove the wrong entry.

Mistake 3: Editing PATH and testing in the old terminal

  • Incorrect: "I fixed PATH, but java still fails, so the fix is wrong."
  • Correct: "The terminal started before my fix. I will open a new one and test again."

Mistake 4: Replacing PATH instead of adding to it

Editing the value as one text line makes it easy to delete existing entries, and then system tools stop working. In a graphical editor, add a new line. In a script, prepend to the existing value, as in "/path/to/jdk/bin:$PATH". Copy the old value somewhere before you edit.

Exercises

Try each exercise yourself before opening the solutions.

Level A: Foundation

A1. What is an environment variable? Give two examples that are not PATH.

أظهر الحل A1

A1. An environment variable is a named text setting that the operating system gives to every program it starts. Examples: JAVA_HOME, USERNAME or USER, HOME or USERPROFILE.

A2. Print your PATH, then write down the separator your system uses and the first three folders.

أظهر الحل A2

A2. Your answer depends on your system. The separator is ; on Windows and : on macOS and Linux. The folders should look like system folders, such as C:\Windows\system32 or /usr/bin.

A3. Which folder of the JDK must be on PATH: the JDK root, bin, or lib? What is the JDK root used for?

أظهر الحل A3

A3. The bin folder, which holds java and javac. The JDK root is the value of JAVA_HOME, which other tools use to find the JDK. lib holds libraries and does not contain the commands.

Level B: Application

B1. Find out which java your shell runs, using where java, Get-Command java, or which java. Compare that folder with the JDK bin folder printed in PATH. Do they match?

أظهر الحل B1

B1. The folder the command reports should be one of the folders in PATH, and normally the JDK bin folder. If the folders differ, you have several Javas and the shell is using the one listed first.

B2. In a terminal, place a wrong entry at the front of PATH for that session only (for example a folder that does not exist), run java -version, and describe what you see. Then repair it for the session.

أظهر الحل B2

B2. The shell skips folders that do not exist or do not hold java, so java -version usually still works through a later entry. If no valid entry is left, the command fails with "not recognized" or "command not found". Repair the session by setting PATH again with the correct folder first, or by closing that terminal and opening a new one. Your exact output depends on your system.

B3. Compile and run EnvPeek.java from this lesson. Which PATH entries does it show, and does the list agree with what your shell printed? Is JAVA_HOME set on your machine?

أظهر الحل B3

B3. The list should match what your shell printed, because the program inherited the terminal's environment. JAVA_HOME is either a folder path or (not set). Both are valid results.

Level C: Challenge

C1. You changed a PATH entry in the Environment Variables dialog and clicked OK. A terminal you opened an hour ago still shows the old value. A teammate says "restart the computer". Explain what is really needed and what you would do first.

أظهر الحل C1

C1. The old terminal does not need a restart of the computer. It only needs to be replaced: closing it and opening a new terminal gives a fresh copy of the stored PATH. A reboot would work as a side effect, because it closes everything, but it is unnecessary. First step: open a new terminal and run the check.

C2. A machine has two JDKs, one for the course baseline and an older one for another project. Describe a safe way to choose which one a terminal uses, without uninstalling either, and say how you would confirm the choice.

أظهر الحل C2

C2. Option: keep both installed and put the wanted JDK's bin folder first in PATH for the terminal, with a session-only command such as the export or $env:PATH lines in this lesson. In a project that uses JAVA_HOME, set JAVA_HOME to the wanted JDK in that terminal as well. Confirm with java -version, javac -version, and where java or which java, and check that the versions and the folder match the one you intended. Because the change is session-only, closing the terminal returns you to the default.

Mini Challenge

Run a safe "break and fix" on your own machine, in the same way the lab requires. Use a session-only change, so that nothing is lost if you make a mistake.

  1. Open a terminal and print both versions to show the working state. Record the output.
  2. In that terminal, remove the JDK's bin folder from PATH for the session (in PowerShell, assign a copy of $env:PATH with the JDK folder removed; in Bash or Zsh, set PATH to a short list such as /usr/bin:/bin). Run java -version and record the error.
  3. In the same terminal, put the folder back. Run java -version and record the result.
  4. Explain, in two sentences, why a new terminal would have shown the working state from the start.

Check your work: your notes show three states (working, broken, fixed), the error message is copied exactly, and your explanation mentions inheritance at start time. Do not edit your permanent system settings for this challenge, because the lab covers that route.

Summary & Next Lesson

Key takeaways

  • An environment variable is a named text setting that programs inherit when they start.
  • PATH is an ordered list of folders the shell searches for commands. Windows separates entries with ;, macOS and Linux with :.
  • Put the JDK's bin folder on PATH. JAVA_HOME holds the JDK root and is read by many tools.
  • "Command not found" means no folder on PATH holds the command. Check installation, the PATH entry, the order, and the terminal's age.
  • A change to PATH shows up only in terminals opened afterwards. Open a new terminal to test.
  • where or which shows which program the shell would run.

Next lesson

You can now install the JDK and fix a broken PATH. The next lesson, "Installing and tour of IntelliJ IDEA", adds the editor that will carry most of your work: an IDE that finds the JDK for you, highlights errors, and runs programs at the click of a button.

Self-check

  1. What does PATH contain?
  2. Which PATH separator does Windows use?
  3. You fixed PATH but the terminal you were using still fails. Why?
  4. Which folder goes on PATH: the JDK root or its bin folder?
  5. What is JAVA_HOME usually set to?
أظهر الإجابات
  1. An ordered list of folders that the shell searches for commands.
  2. A semicolon ;. (macOS and Linux use a colon :.)
  3. The terminal was opened before the change and still has the old copy. Open a new terminal.
  4. The bin folder.
  5. The JDK's root folder, not its bin folder.

References

  • Microsoft Learn, about_Environment_Variables. Supports these points: environment variables are strings inherited by child processes; Windows has Machine, User, and Process scopes; names are case-sensitive on macOS and Linux; a change made in PowerShell affects only the current session; $Env:PATH is a list of folders separated by ; on Windows and : elsewhere; the Control Panel route to the Environment Variables editor; and the ~/.bashrc and ~/.zshrc start-up files on non-Windows systems.
  • Oracle, JDK 21 installation overview. Used only for the default Windows install folder. It does not describe PATH or JAVA_HOME.
  • Oracle, java command reference (JDK 21). Supports the commands being found by name and the version options. I read only the first part of this page, so the JAVA_HOME details are not verified there.
  • The Open Group, Base Specifications, Environment Variables. A search summary indicated that it lists PATH among standard variables and notes that the colon is the separator, so directory names in PATH should not contain one. I did not read the page in full, and I did not verify the exact "search in order, first match wins" wording there. That behaviour is standard shell practice and is stated as such.
  • Not verified on an official page: the exact error messages of each shell (they vary by version), the exact output of where, which, and Get-Command, the JAVA_HOME build-tool convention, and which start-up file a given macOS Terminal reads. The text hedges these.

التطبيق

طبّق هذا الدرس بمختبر الوحدة وتمارينها واختبارها.

المختبر والتمارين الاختبار

تعليم الدرس كمكتمل اختياري ويمكنك التراجع عنه في أي وقت. يبقى تقدمك محفوظًا في هذا المتصفح.

اكتب للبحث في المستويات والمراحل والوحدات والدروس.