Bash is the command language of most Linux and macOS terminals: you type commands to navigate
folders, manage files, and automate tasks. You run it interactively or save commands in a .sh
script.
Where am I, what's here?
pwd prints the current folder; ls lists its contents.
pwd # => /home/ada/projects
ls # names only
ls -la # long format, including hidden filesMove around
cd changes directory. . is here, .. is the parent, ~ is your home folder.
cd projects/app # go into a subfolder
cd .. # up one level
cd ~ # back to home
cd - # back to the previous folderCreate files and folders
mkdir makes folders, touch makes an empty file.
mkdir notes # one folder
mkdir -p src/app/utils # create nested folders in one go
touch todo.txt # empty file (or update its timestamp)Copy, move, rename, delete
cp copies, mv moves or renames, rm deletes. There is no undo — be careful.
cp file.txt backup.txt # copy
cp -r src/ dist/ # copy a folder and its contents
mv old.txt new.txt # rename
mv report.txt ~/Documents/ # move
rm file.txt # delete a file
rm -r folder/ # delete a folder and everything in itLook inside a file
cat dumps the whole file; head/tail show the start or end; less scrolls page by page.
cat notes.txt # print the whole file
head -n 5 log.txt # first 5 lines
tail -n 20 log.txt # last 20 lines
tail -f log.txt # follow new lines as they're written (Ctrl-C to stop)
less big.txt # scroll (q to quit)Find files and search text
find locates files by name; grep searches for text inside files.
find . -name "*.js" # all .js files under the current folder
grep "error" log.txt # lines containing "error"
grep -ri "todo" src/ # recursive, case-insensitive search in src/
grep -n "fix" notes.txt # show line numbersPipes and redirection
A pipe | feeds one command's output into the next; > writes output to a file, >> appends.
ls -la | grep ".txt" # list, keep only .txt lines
cat log.txt | wc -l # count lines in the file
echo "hello" > greeting.txt # write (overwrites the file)
echo "again" >> greeting.txt # append a lineVariables
Assign with no spaces around =; read the value back with a $ prefix.
name="Ada"
echo "Hello, $name" # => Hello, Ada
greeting="Hi ${name}!" # braces help when text follows the name
echo "$greeting" # => Hi Ada!Command substitution
Wrap a command in $( ) to capture its output into a variable.
today=$(date +%Y-%m-%d)
echo "Today is $today" # => Today is 2026-06-24
files=$(ls | wc -l)
echo "$files files here"Conditionals
if runs a block when a test passes. Use [ ... ] for the test, with spaces inside the brackets.
if [ -f config.json ]; then
echo "config exists"
else
echo "no config"
fiCommon test flags: -f file exists, -d folder exists, -z string is empty.
if [ -z "$name" ]; then
echo "name is empty"
fiCompare values
Numbers use -eq/-lt/-gt; strings use = and !=.
count=5
if [ "$count" -gt 3 ]; then
echo "more than three" # => more than three
fi
if [ "$name" = "Ada" ]; then
echo "hi Ada"
fiLoops
for repeats over a list; while repeats while a condition holds.
for file in *.txt; do
echo "Found $file"
donecount=1
while [ "$count" -le 3 ]; do
echo "count is $count"
count=$((count + 1))
doneFunctions
Group commands under a name; refer to arguments as $1, $2, and so on.
greet() {
echo "Hello, $1!"
}
greet "Ada" # => Hello, Ada!Write a script
Start the file with a shebang line so the system knows to run it with Bash.
#!/usr/bin/env bash
echo "Backing up..."
cp -r src/ backup/
echo "Done."Make it executable once, then run it by path.
chmod +x backup.sh # mark as runnable
./backup.sh # run itFile permissions
chmod sets who can read/write/execute; ls -l shows the current permissions.
ls -l script.sh # => -rw-r--r-- 1 ada ada ...
chmod +x script.sh # add execute permission
chmod 644 notes.txt # owner read/write, others read-onlyEnvironment and PATH
Environment variables configure your shell; PATH lists folders searched for commands.
echo "$HOME" # => /home/ada
echo "$PATH" # colon-separated folders
export API_KEY="abc123" # set a variable for this session and child processesHandy shortcuts
These save time at the prompt every day.
history # list recent commands
!! # run the previous command again
clear # clear the screen (or Ctrl-L)
which node # show the full path of a command
man ls # open the manual for a command (q to quit)Chaining commands
&& runs the next command only if the previous one succeeded; ; runs regardless.
mkdir build && cd build # cd only if mkdir worked
npm install ; npm test # run both, even if install fails
command || echo "it failed" # run the fallback only on failure