متغيرات البيئة وPATH
في هذا الدرس 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
PATHis and how the terminal uses it to find a command. - Print
PATHin 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
PATHappears only in terminals opened afterwards. - Add a folder to
PATHfor one terminal session, and describe how to make it permanent. - Explain what
JAVA_HOMEholds and how it differs from aPATHentry.
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:
| Name | Typical meaning |
|---|---|
PATH | The list of folders searched for commands |
JAVA_HOME | The folder where the JDK is installed |
HOME (macOS and Linux) or USERPROFILE (Windows) | Your personal folder |
USERNAME or USER | Your 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):
C:\Windows\system32;C:\Windows;C:\Program Files\Java\jdk-<version>\binand a Unix-like one:
/usr/local/bin:/usr/bin:/bin:/usr/lib/jvm/java-<version>-openjdk/binThe 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
| Shell | Command to print PATH |
|---|---|
| Windows Command Prompt | echo %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:
PowerShell: $env:PATH -split ';'
Bash or Zsh: echo "$PATH" | tr ':' '\n'You can also ask the shell which program it would run:
| Shell | Command |
|---|---|
| Windows Command Prompt | where java |
| Windows PowerShell | Get-Command java |
| macOS and Linux | which 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:
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:
'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:
- Not installed. There is no JDK on the machine.
- Installed but not on
PATH. Thebinfolder is not on the list. - Wrong folder on
PATH. The entry points to the JDK folder instead of itsbinfolder, or contains a typo or an outdated version number. - Old terminal. The change was made after the terminal started, so this terminal still has the old copy.
- Typing mistake. The command is
java, notJavaon a case-sensitive system, and notjave.
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:
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'sbinfolder 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~/.bashrcfor Bash and~/.zshrcfor 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:
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:
$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:
- He lists the JDK folder on disk and finds that the compilers are in
.../jdk-<version>/bin. - He prints
PATHand does not see that folder. - He adds it for the session:
export PATH="/path/to/jdk-<version>/bin:$PATH"(his own path in place of the example). javac -versionnow prints a version. The fix works for this terminal only.- To make it permanent, he adds the same
exportline 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, butjavastill 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.
- Open a terminal and print both versions to show the working state. Record the output.
- In that terminal, remove the JDK's
binfolder fromPATHfor the session (in PowerShell, assign a copy of$env:PATHwith the JDK folder removed; in Bash or Zsh, setPATHto a short list such as/usr/bin:/bin). Runjava -versionand record the error. - In the same terminal, put the folder back. Run
java -versionand record the result. - 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.
PATHis an ordered list of folders the shell searches for commands. Windows separates entries with;, macOS and Linux with:.- Put the JDK's
binfolder onPATH.JAVA_HOMEholds the JDK root and is read by many tools. - "Command not found" means no folder on
PATHholds the command. Check installation, thePATHentry, the order, and the terminal's age. - A change to
PATHshows up only in terminals opened afterwards. Open a new terminal to test. whereorwhichshows 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
- What does
PATHcontain? - Which
PATHseparator does Windows use? - You fixed
PATHbut the terminal you were using still fails. Why? - Which folder goes on
PATH: the JDK root or itsbinfolder? - What is
JAVA_HOMEusually set to?
أظهر الإجابات
- An ordered list of folders that the shell searches for commands.
- A semicolon
;. (macOS and Linux use a colon:.) - The terminal was opened before the change and still has the old copy. Open a new terminal.
- The
binfolder. - The JDK's root folder, not its
binfolder.
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:PATHis a list of folders separated by;on Windows and:elsewhere; the Control Panel route to the Environment Variables editor; and the~/.bashrcand~/.zshrcstart-up files on non-Windows systems. - Oracle, JDK 21 installation overview. Used only for the default Windows install folder. It does not describe
PATHorJAVA_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_HOMEdetails are not verified there. - The Open Group, Base Specifications, Environment Variables. A search summary indicated that it lists
PATHamong standard variables and notes that the colon is the separator, so directory names inPATHshould 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, andGet-Command, theJAVA_HOMEbuild-tool convention, and which start-up file a given macOS Terminal reads. The text hedges these.
التطبيق
طبّق هذا الدرس بمختبر الوحدة وتمارينها واختبارها.
تعليم الدرس كمكتمل اختياري ويمكنك التراجع عنه في أي وقت. يبقى تقدمك محفوظًا في هذا المتصفح.