How to buildOctober 11, 202610 min read
Docker and deploymentStep 1 of 8

Terminal and command line for developers

In short

A terminal is the window for text commands; a shell (bash, zsh, PowerShell) is the program that reads and runs them. A developer needs about a dozen commands: change directory (cd), list contents (ls), create and delete files, run node or npm, set an environment variable and chain commands with a pipe. Below are all of these steps with real output and PowerShell equivalents for Windows.

TutorialLevel: BeginnerTerminal & CLIPractice: ~45–90 min

After this you will be able to

  • Navigate the file system with pwd, ls and cd and tell an absolute path from a relative one
  • Create, copy, rename and delete files and directories without risking your data
  • Run node and npm with arguments and explain how the shell finds a program through PATH
  • Set environment variables, chain commands with pipes and redirect output in bash and PowerShell

Verified with

bash 5.2 (Ubuntu 24.04)Git Bash 5.3 (Git for Windows 2.55)PowerShell 7.6GNU coreutils 9.4Node.js 24.18npm 11.16

Checked against docs: October 11, 2026

Contents
  1. 01Terminal, shell and command: what is what
  2. 02Windows, macOS and Linux: one idea, different shells
  3. 03Navigation: pwd, ls, cd and paths
  4. 04Files and directories: mkdir, cp, mv, rm — and why rm -rf is dangerous
  5. 05Running programs, PATH and environment variables
  6. 06Streams and pipelines: |, >, >>, 2> and grep
  7. 07Permissions: chmod and executable scripts
  8. 08Practice: create and run a project from the terminal

Terminal, shell and command: what is what

Almost every development tool — Node.js, npm, Git, Docker — works from the command line first. In a graphical interface you click buttons; in a terminal you type short text commands and the computer answers in text. It is faster, more precise and easy to repeat: the same sequence of commands can be saved to a file and run again.

Three words get mixed up. MDN separates them like this: a terminal is the window program that starts a shell and connects to it; the shell is your session with its own settings, and it parses and runs commands; the command line is the line where the cursor blinks. In practice “terminal” and “command line” are used interchangeably, and that is fine.

Terminal

What it is
A window that displays text and passes your input to the shell
Examples
Terminal on macOS, Windows Terminal, the VS Code integrated terminal

Shell

What it is
A program that reads a command, finds the right program and starts it
Examples
bash, zsh, PowerShell

Command

What it is
A program name or shell built-in plus arguments
Examples
ls -l src, node index.js --port 3000

Prompt

What it is
The text before the cursor: the shell is ready for a command
Examples
$ in bash, PS> in PowerShell

Windows, macOS and Linux: one idea, different shells

Linux always ships a terminal, usually with bash. On macOS the default shell has been zsh since version 10.15 (per Apple Support); the commands in this lesson work the same way there. Windows opens PowerShell by default; for familiar Unix commands people install Git Bash — part of Git for Windows, it emulates bash — or a full Linux through WSL, which MDN recommends.

The key difference in PowerShell: its commands (cmdlets) pass .NET objects to each other, not text. For convenience it has aliases with familiar names: ls, cd, cat, rm call native PowerShell commands. You can check what an alias stands for like this:

PowerShell
PS> Get-Command ls, cd, pwd, cat, rm, cp, mv | Select-Object Name, Definition

Name Definition
---- ----------
ls   Get-ChildItem
cd   Set-Location
pwd  Get-Location
cat  Get-Content
rm   Remove-Item
cp   Copy-Item
mv   Move-Item
PowerShell 7.6 on Windows 11: which commands stand behind the familiar names (real output).

Where am I

bash
pwd
PowerShell 7
Get-Location (pwd)

List files

bash
ls -la
PowerShell 7
Get-ChildItem -Force (ls)

Change directory

bash
cd src
PowerShell 7
Set-Location src (cd)

Create a directory

bash
mkdir -p a/b
PowerShell 7
New-Item -ItemType Directory a/b

Create an empty file

bash
touch README.md
PowerShell 7
New-Item README.md -ItemType File

Show a file

bash
cat file.txt
PowerShell 7
Get-Content file.txt (cat)

Copy / move

bash
cp a b / mv a b
PowerShell 7
Copy-Item a b / Move-Item a b

Delete a directory with contents

bash
rm -r dir
PowerShell 7
Remove-Item -Recurse dir

Find lines

bash
grep api access.log
PowerShell 7
Select-String api access.log

Count lines

bash
… | wc -l
PowerShell 7
(… | Measure-Object).Count

Environment variable

bash
export APP_ENV=test
PowerShell 7
$env:APP_ENV = "test"

Where a program lives

bash
command -v node
PowerShell 7
(Get-Command node).Source
Cheat sheet: bash (macOS, Linux, Git Bash) and PowerShell 7

Navigation: pwd, ls, cd and paths

The shell is always “in” some directory — the current working directory. At startup it is your home directory. pwd shows where you are, ls shows what is around, cd moves to another directory. mkdir -p creates a directory together with any missing parents.

terminal
$ pwd
/home/ubuntu
$ mkdir -p projects/hello/src
$ cd projects/hello
$ pwd
/home/ubuntu/projects/hello
$ ls
src
$ cd src
$ pwd
/home/ubuntu/projects/hello/src
$ cd ..
$ cd ../..
$ pwd
/home/ubuntu
$ cd /home/ubuntu/projects/hello/src
$ cd ~
$ pwd
/home/ubuntu
bash 5.2, Ubuntu 24.04, user ubuntu: moving between directories (real output, last step of the session omitted).
  • An absolute path starts at the root /: /home/ubuntu/projects/hello/src leads to the same place wherever you are.
  • A relative path starts from the current directory: cd src works only if src is right here.
  • .. is the parent directory, . the current one, ~ your home. cd with no arguments also takes you home.
  • The Tab key completes a file or directory name once you have typed the beginning: fewer typos, less typing.
  • Windows paths use backslashes (C:\Users\name), while Git Bash shows the same drive as /c/Users/name.

Files and directories: mkdir, cp, mv, rm — and why rm -rf is dangerous

touch creates an empty file, cp copies, mv moves or renames: a rename is a move into the same directory under a new name. rm deletes a file, rmdir deletes only an empty directory, and rm -r deletes a directory with everything inside. ls -l gives a detailed listing: permissions, owner, size and date.

terminal
$ cd ~/projects/hello
$ touch README.md
$ echo 'console.log("hello")' > src/index.js
$ cat src/index.js
console.log("hello")
$ cp src/index.js src/index.backup.js
$ mv src/index.backup.js old.js
$ ls -l . src
.:
total 8
-rw-r--r-- 1 ubuntu ubuntu    0 Oct 11 22:02 README.md
-rw-r--r-- 1 ubuntu ubuntu   21 Oct 11 22:02 old.js
drwxr-xr-x 2 ubuntu ubuntu 4096 Oct 11 22:02 src

src:
total 4
-rw-r--r-- 1 ubuntu ubuntu 21 Oct 11 22:02 index.js
$ rm old.js
$ rmdir src
rmdir: failed to remove 'src': Directory not empty
$ rm -r src
$ ls
README.md
bash 5.2, Ubuntu 24.04: creating, copying, renaming and deleting (real output, some steps of the session omitted).
  • Before deleting, run pwd and ls with the same path — make sure you see exactly what you are about to remove.
  • For manual work use rm -i: the shell asks for confirmation for each file.
  • Do not copy commands with rm -rf and sudo from the internet until you understand every part.
  • Run risky experiments in a separate test directory or in a container.

Running programs, PATH and environment variables

When you type node index.js --port 3000, the first word is the program name and the rest are arguments: the program receives them as a list and decides what to do with them. Flags usually start with one dash (-l) or two (--port). If the name has no slash, the shell looks for the program in the directories listed in the PATH environment variable — in order, until it finds an executable file. That is how POSIX describes it; on Linux and macOS the directories in PATH are separated by colons, on Windows by semicolons.

terminal
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
$ command -v bash ls
/usr/bin/bash
/usr/bin/ls
$ type cd
cd is a shell builtin
$ node --version
bash: node: command not found
$ echo $?
127
bash 5.2, a clean Ubuntu 24.04 image without Node.js: program lookup via PATH and exit code 127 (real output, some steps of the session omitted).

command -v shows which file will run, and type identifies shell built-ins: cd is not a program but part of the shell itself. The exit status is stored in $?: 0 means success, any other number is an error. POSIX assigns 127 to “command not found” and 126 to “found but not executable”. A command not found message nearly always means one of two things: the program is not installed, or its directory is not in PATH (restarting the terminal after installation often helps).

Environment variables are name=value pairs a process inherits from its parent at startup. They pass settings to programs without changing code: the mode, the port, the database address. A plain shell variable is visible only to the shell itself; export makes it part of the environment of child processes. Writing APP_ENV=test command sets the variable for that one command only.

terminal
$ echo $HOME
/home/ubuntu
$ GREETING=hello
$ echo $GREETING
hello
$ bash -c 'echo "child: [$GREETING]"'
child: []
$ export GREETING
$ bash -c 'echo "child: [$GREETING]"'
child: [hello]
$ APP_ENV=test bash -c 'echo "APP_ENV=$APP_ENV"'
APP_ENV=test
$ echo "after: [$APP_ENV]"
after: []
$ unset GREETING
bash 5.2, Ubuntu 24.04: a plain variable, export and a one-command variable (real output, some steps of the session omitted).

In PowerShell environment variables are available as $env:NAME. Microsoft's documentation notes that such a change affects only the current session and is inherited by child processes; for a permanent value you put the variable in your PowerShell profile or system settings. PowerShell has no APP_ENV=test command form — set the variable on a separate line.

PowerShell
PS> $env:APP_ENV = "test"
PS> pwsh -NoProfile -c '"child: [$env:APP_ENV]"'
child: [test]
PS> Remove-Item Env:APP_ENV
PS> "[$env:APP_ENV]"
[]
PS> $env:PATH -split ";" | Select-String nodejs
C:\Program Files\nodejs
PowerShell 7.6, Windows 11: a session environment variable and finding the Node.js directory in PATH (real output from two runs).

Streams and pipelines: |, >, >>, 2> and grep

Every program has three standard streams: input (stdin, number 0), output (stdout, 1) and errors (stderr, 2). By default output and errors go to the screen. The pipe | connects one command's output to the next command's input — as POSIX puts it, the standard output of command1 is connected to the standard input of command2. This is how small utilities combine into the tool you need: grep filters lines, wc -l counts them, sort sorts them.

terminal
$ printf 'GET /\nPOST /api/lead\nGET /about\nGET /api/health\n' > access.log
$ grep api access.log
POST /api/lead
GET /api/health
$ grep api access.log | wc -l
2
$ grep api access.log > api.txt
$ echo 'GET /api/price' >> api.txt
$ cat api.txt
POST /api/lead
GET /api/health
GET /api/price
$ ls missing.txt
ls: cannot access 'missing.txt': No such file or directory
$ echo $?
2
$ ls missing.txt 2> errors.txt
$ cat errors.txt
ls: cannot access 'missing.txt': No such file or directory
$ mkdir demo && cd demo && echo "created and entered"
created and entered
$ cd ~
$ ls missing.txt && echo "never printed" || echo "ls failed, exit code $?"
ls: cannot access 'missing.txt': No such file or directory
ls failed, exit code 2
bash 5.2, Ubuntu 24.04: searching a request log, redirections and exit codes (real output, some steps omitted).

a | b

What it does
The output of a becomes the input of b

a > file

What it does
Write output to a file, overwriting it

a >> file

What it does
Append output to the end of a file

a 2> file

What it does
Write only errors to a file

a > file 2>&1

What it does
Write both output and errors to a file

a && b

What it does
Run b only if a succeeded (exit code 0)

a || b

What it does
Run b only if a failed

>, >>, 2>, |, && and || also work in PowerShell 7 — the last two arrived in version 7. But PowerShell pipelines carry objects, so instead of grep and wc you use Select-String and Measure-Object. A classic beginner mistake is > instead of >>: one extra angle bracket silently wipes the file.

Permissions: chmod and executable scripts

On Linux and macOS every file has permissions for three classes: the owner, the group and everyone else. Each class gets read (r), write (w) and execute (x). In ls -l output the first character is the type (d for a directory, - for a file), followed by three triplets of permissions. You can run a script as ./build.sh only if it has the x bit; otherwise the shell answers Permission denied.

terminal
$ printf '#!/usr/bin/env bash\necho "Build started in $(pwd)"\n' > build.sh
$ ls -l build.sh
-rw-r--r-- 1 ubuntu ubuntu 51 Oct 11 22:02 build.sh
$ ./build.sh
bash: ./build.sh: Permission denied
$ chmod +x build.sh
$ ls -l build.sh
-rwxr-xr-x 1 ubuntu ubuntu 51 Oct 11 22:02 build.sh
$ ./build.sh
Build started in /home/ubuntu
$ chmod 600 build.sh
$ ls -l build.sh
-rw------- 1 ubuntu ubuntu 51 Oct 11 22:02 build.sh
bash 5.2, Ubuntu 24.04, user ubuntu: permissions of a new file, chmod +x and chmod 600 (real output).

chmod +x build.sh

Permissions
Add execute for everyone
When to use
Your own script you want to run as ./build.sh

chmod 755 (rwxr-xr-x)

Permissions
Owner — everything, others — read and execute
When to use
Scripts and directories others may use

chmod 644 (rw-r--r--)

Permissions
Owner — read and write, others — read
When to use
Regular project files

chmod 600 (rw-------)

Permissions
Owner only, no execute
When to use
Private files: keys, .env on a server

The digits are octal: r = 4, w = 2, x = 1, summed for each class. The first line of the script, #!/usr/bin/env bash (the shebang), tells the system which program should run it. Without the x bit you can still run a script explicitly: bash build.sh.

Practice: create and run a project from the terminal

Let us put it all together: create a project directory, initialise npm, write a script that reads its arguments and an environment variable, and run it three ways. You need Node.js installed. In Node.js command-line arguments are available as process.argv and environment variables as process.env.

index.js
const name = process.env.USER_NAME ?? "world";
const args = process.argv.slice(2);
console.log(`Hello, ${name}!`);
console.log(`Arguments: ${args.join(" ") || "none"}`);
Create the file in your editor inside ~/projects/hello-cli. Checked with Node.js 24.18.
terminal
$ node --version
v24.18.0
$ npm --version
11.16.0
$ mkdir -p ~/projects/hello-cli && cd ~/projects/hello-cli
$ npm init -y > /dev/null
$ ls
package.json
$ node index.js
Hello, world!
Arguments: none
$ node index.js --port 3000
Hello, world!
Arguments: --port 3000
$ USER_NAME=Asel node index.js
Hello, Asel!
Arguments: none
$ npm pkg set scripts.start="node index.js"
$ npm start -- --verbose

> hello-cli@1.0.0 start
> node index.js --verbose

Hello, world!
Arguments: --verbose
bash 5.2 in the node:24.18.0-bookworm-slim image (real output; index.js was created between the ls and node index.js steps).

The double dash in npm start -- --verbose is a boundary: npm does not parse anything after it and passes it to the script, as the npm run documentation describes. The same scenario in PowerShell 7:

PowerShell
PS> New-Item -ItemType Directory hello-cli -Force | Out-Null
PS> Set-Location hello-cli
PS> npm init -y > $null
PS> node index.js --port 3000
Hello, world!
Arguments: --port 3000
PS> $env:USER_NAME = "Asel"
PS> node index.js
Hello, Asel!
Arguments: none
PS> Remove-Item Env:USER_NAME
PS> npm pkg set scripts.start="node index.js"
PS> npm start -- --verbose
> hello-cli@1.0.0 start
> node index.js --verbose
Hello, world!
Arguments: --verbose
PowerShell 7.6, Windows 11, Node.js 24.18 (real output).
  • node --version prints a version, not command not found
  • Without the variable the script prints Hello, world!; with USER_NAME=Asel it prints Hello, Asel!
  • Arguments after the file name appear in the Arguments: line
  • package.json now has a start script, and npm start runs it

The next step is Git: it runs in the same terminal, and confident navigation between directories is needed from the very first command.

How this was verified5 · passedchecked 11 October 2026

“Run” means the code was executed in a scratch project or container and the output in the article comes from that run. “Partial” means it was checked against stubs instead of external services. “Not run” means it needs a device, an account or a key; the steps were checked against the official documentation. The verification project files and run logs are kept in the InterLAB archive.

Tell us about your task — we'll review your request and get back to you

Got a project?
We'll scope and estimate it — for free.

Tell us about the product or the problem. After reviewing the task we'll come back with an architecture, a timeline and a price for the first version.

  • Scope and risks estimated before we start
  • NDA — yours or ours
  • Work starts within a week

Please do not send passwords, access keys or source code through this form — we will agree a safe way to share access separately.

By clicking the button you agree to the processing of your personal data.