Linux Operating Systems Fundamentals · Lesson 9
Writing Scripts
Shell variables and startup files, Bash scripting with input, tests, loops, and functions, job control and signals, and scheduling with at and cron.
Lesson purpose
Administrators repeat the same tasks constantly: checking disk space, creating accounts, rotating backups. A shell script turns a sequence of commands into a reusable, testable tool, and scheduling runs it without anyone watching. This lesson builds from shell variables and startup files to complete Bash scripts with input, decisions, loops, and functions. It then covers running scripts in the background, controlling jobs and signals, and scheduling work with at and cron.
Learning objectives
- Distinguish local and environment (global) variables, set and export them, and explain which startup files each kind of shell reads.
- Create aliases and make variables and aliases persistent.
- Combine commands with
;, redirection, and pipes, and write, permission, and run a script that begins with a shebang line. - Use
echo, variables, positional parameters,read, exit status, command substitution, and arithmetic in scripts. - Control script flow with
if/test,case,for,while/until, and functions. - Run jobs in the background, keep them running after logout with
nohup, send signals, and manage jobs withjobs,bg, andfg. - Schedule one-time jobs with
atand recurring jobs withcron, and recognize systemd timers.
LPIC-1 exam focus
- 105.2 Customize or write simple scripts
- 107.2 Automate system administration tasks by scheduling jobs
1. Shell variables
The shell stores data in memory as named variables that commands and scripts can read. By convention, system variables are UPPERCASE. Use lowercase for your own variables so you don’t accidentally overwrite a system variable.
Environment (global) and local variables
| Local (shell) variable | Environment (global) variable | |
|---|---|---|
| Visible in | Only the current shell | The current shell and every child process it starts |
| Created by | name=value |
export name (or export name=value) |
| Listed by | set (shows local and environment variables, plus functions) |
printenv or env |
$ echo $HOME # read a variable: put $ in front of its name
/home/rich
$ test='testing a long string' # no spaces around =; quote values that contain spaces
$ bash # start a child shell
$ echo $test # empty: local variables aren't inherited
$ exit
$ export test # export by NAME (no $)
$ bash
$ echo $test
testing a long string
The two classic mistakes:
test2 = testruns a command namedtest2. There must be no spaces around=.export $testexports a variable named after the value oftest. Export the name:export test. One of the course slides showsexport $test, which is wrong.
A child process can never change its parent’s variables. When a child shell exits, any variables it set are gone.
Common environment variables
| Variable | Meaning |
|---|---|
HOME |
Your home directory |
USER / LOGNAME |
Your username |
UID |
Your numeric user ID |
PATH |
Directories searched for commands, separated by colons |
PWD / OLDPWD |
Current and previous directory |
SHELL |
Your login shell |
PS1 / PS2 |
Primary and continuation prompts |
HOSTNAME |
Host name |
LANG |
Locale (Lesson 6) |
TZ |
Time zone override (Lesson 6) |
EDITOR / PAGER |
Preferred editor and pager, used by tools such as crontab -e and man |
TERM |
Terminal type |
HISTSIZE |
Number of commands kept in history |
DISPLAY |
X11 display for GUI programs |
LD_LIBRARY_PATH |
Extra directories to search for shared libraries |
MAIL |
Your mail spool file |
$ export PATH="$PATH:$HOME/bin" # add a directory to the command search path
$ unset test # remove a variable
2. Startup files: where the environment comes from
Bash reads different files depending on how it starts.
| Shell type | How it starts | Files read |
|---|---|---|
| Login shell | Console login, SSH login, su - |
/etc/profile (and /etc/profile.d/*.sh), then the first one found of ~/.bash_profile, ~/.bash_login, ~/.profile |
| Interactive non-login shell | A new terminal window in the GUI, or typing bash |
~/.bashrc, which usually sources /etc/bash.bashrc (Debian) or /etc/bashrc (Red Hat) |
| Non-interactive shell | Running a script | The file named in $BASH_ENV, if it’s set (usually it isn’t) |
- On logout, a login shell runs
~/.bash_logout. - Most
~/.bash_profilefiles source~/.bashrc, so interactive settings apply to login shells too. - System-wide settings for every user go in
/etc/profile.d/(preferred) or/etc/profile. Personal settings go in~/.bashrc(aliases, functions, prompt) or~/.bash_profile(environment variables). - The files beginning with a dot are hidden, so use
ls -ato see them. New users get copies from/etc/skel(Lesson 7). - Reload a file you’ve edited, without logging out, by sourcing it:
source ~/.bashrcor. ~/.bashrc.
3. Aliases
An alias is a shortcut name for a command and its options.
$ alias -p # list current aliases
alias ll='ls -l --color=auto'
$ alias li='ls -il' # create an alias
$ li
$ unalias li # remove it
$ \ls # run the real ls, skipping the alias
- Aliases behave like local variables: they exist only in the shell where you defined them and aren’t inherited by child shells.
- Put aliases in
~/.bashrcso every interactive shell gets them. - Many distributions already alias
ls(to add--color) and sometimesrm -i.type lsshows whether a name is an alias.
4. Building blocks: sequences, redirection, and pipes
Several commands on one line
$ date ; who # run one, then the other, regardless of success
$ mkdir backup && cp *.conf backup/ # run the second only if the first succeeds
$ ping -c1 server || echo "Server down" # run the second only if the first fails
File descriptors and redirection
| Descriptor | Name | Default |
|---|---|---|
| 0 | STDIN | Keyboard |
| 1 | STDOUT | Terminal |
| 2 | STDERR | Terminal |
| Operator | Effect |
|---|---|
> file |
Send STDOUT to a file, overwriting it |
>> file |
Append STDOUT to a file |
2> file |
Send STDERR (error messages) to a file |
&> file or > file 2>&1 |
Send both STDOUT and STDERR to a file |
< file |
Read STDIN from a file |
2>/dev/null |
Throw error messages away |
$ date > today.txt
$ who >> today.txt
$ find / -name '*.conf' 2>/dev/null > conf-list.txt
Pipes
| sends one command’s STDOUT into the next command’s STDIN. There’s no limit to how many commands you can chain:
$ ls | sort
$ cut -d: -f7 /etc/passwd | sort | uniq -c | sort -rn # count login shells
Metacharacters and quoting
Characters such as > < | & ; $ * ? ' " \ have special meanings to the shell. To use one literally, escape it:
\escapes one character:echo 5 \> 3.- Single quotes keep everything literal:
echo '$HOME'prints$HOME. - Double quotes keep spaces together but still expand
$variablesand$(commands):echo "Home is $HOME".
5. Writing and running a script
A shell script is a plain text file of commands. Write scripts in a text editor (nano, vi, gedit, KWrite), never a word processor, because a word processor adds hidden formatting characters.
#!/bin/bash
# test1.sh - show the date and who is logged in
date
who
- Shebang (
#!) on the first line tells the kernel which interpreter runs the file. Use#!/bin/bashfor Bash scripts.#!/bin/shmay be Dash on Debian and Ubuntu, which lacks Bash features. - Comments begin with
#. Use them to explain why the script does something. - Each line is one command, so no semicolons are needed.
- A
.shextension is a convention that makes scripts easy to recognize. Linux doesn’t require it.
Making it run
$ test1.sh
test1.sh: command not found # the current directory isn't in $PATH
$ ./test1.sh
bash: ./test1.sh: Permission denied # no execute permission
$ chmod u+x test1.sh
$ ./test1.sh
Thu Sep 24 19:48:27 CDT 2026
rich :0 2026-09-24 19:15 (:0)
| How you run it | What happens |
|---|---|
./script.sh |
Runs in a child shell. Needs execute permission and a shebang. |
bash script.sh |
Runs in a child Bash shell. Execute permission isn’t needed. |
source script.sh or . script.sh |
Runs in the current shell, so it can see and change your local variables. Used for startup files. |
exec ./script.sh |
Replaces the current shell with the script. When the script ends, the terminal session ends too. |
The book says to use exec so a script can see local variables. That’s incorrect: exec replaces your shell, so the terminal closes when the script finishes. To run a script in the current shell, use source (or .).
To run your own scripts by name, put them in a directory on PATH, such as ~/bin (many distributions add it automatically if it exists) or /usr/local/bin for scripts shared by all users.
6. Output, variables, and arguments in scripts
echo
#!/bin/bash
echo The current date and time is:
date
echo # blank line
echo "Let's see who's logged into the system:"
who
- Use double quotes when the text contains a single quote (an apostrophe).
echo -nprints without a trailing newline, which is useful for prompts.printfgives precise formatting:printf "%-10s %5d\n" "$user" "$count".
Variables in scripts
#!/bin/bash
echo "User info for userid: $USER"
echo "UID: $UID"
echo "HOME: $HOME"
days=10
guest=Katie
echo "$guest checked in $days days ago"
echo "${guest}'s stay: ${days}days" # braces separate the name from following text
- Shell variables are text strings. There are no separate data types; arithmetic just interprets the string as a number.
- Always double-quote variable references (
"$file") so values that contain spaces stay together. - Variables created in a script disappear when the script ends. A script can’t export variables back to the shell that started it; only sourcing changes the current shell.
Positional parameters and special variables
| Variable | Contains |
|---|---|
$0 |
The script’s name |
$1 … $9, ${10} |
Command-line arguments |
$# |
Number of arguments |
$@ |
All arguments as separate words (use "$@") |
$* |
All arguments as one string |
$? |
Exit status of the last command |
$$ |
PID of the current shell or script |
$! |
PID of the last background job |
#!/bin/bash
# checkin.sh NAME DAYS
if [ $# -ne 2 ]; then
echo "Usage: $0 NAME DAYS" >&2
exit 1
fi
echo "$1 checked in $2 days ago"
A missing argument produces no error, just an empty value (./test4.sh rich prints “rich checked in days ago”). Check $# and print a usage message.
Reading input
read name # read a line into name
read -p "Enter your name: " first last # prompt; split into words (extra words go to the last variable)
read -p "Enter a number: " # no variable name: the input goes into $REPLY
read -t 5 -p "Name? " name # time out after 5 seconds (read returns non-zero)
read -n1 -p "Continue [Y/N]? " answer # return after 1 character, no Enter needed
read -s -p "Password: " pass; echo # silent: don't echo what's typed
read -s turns off terminal echo. The book says it sets the text color to match the background; that isn’t how it works.
Exit status
- Every command returns an exit status from 0 to 255. 0 means success, and anything else means failure. Check it immediately in
$?, because the next command overwrites it. - End a script with
exit Nto report success or a specific error code to whatever ran it (a user, another script, cron).
$ who > /dev/null ; echo $?
0
$ ls /nonexistent 2>/dev/null ; echo $?
2
7. Command substitution and arithmetic
Command substitution
Command substitution captures a command’s output in a variable:
today=$(date +%F) # preferred form
users=`who | wc -l` # older backtick form
echo "Backup for $today; $users users logged in"
tar -czf "/backup/home-$(date +%F).tgz" /home
The backtick (`) is not a single quote, which confuses many students. $( ) is easier to read and can be nested, so use it in class.
Integer arithmetic
result=$(( 25 * 5 )) # 125 (preferred)
count=$(( count + 1 ))
(( count++ ))
result=$[ 25 * 5 ] # older form shown in the book; still works but is deprecated
echo $(( 7 / 2 )) # 3: Bash math is integers only
echo $(( 7 % 2 )) # 1: remainder
Floating point with bc
$ echo "scale=4; 3.44 / 5" | bc
.6880
$ avg=$(echo "scale=2; $total / $n" | bc)
scale sets the number of decimal places. The default is 0, which is why 3.44 / 5 gives 0 until you set it.
8. Decisions: if, test, and case
if and test
if [ condition ]; then
commands
elif [ other-condition ]; then
commands
else
commands
fi
[ condition ]is another name for thetestcommand. The spaces inside the brackets are required:[ "$a" -eq 1 ].ifactually runs a command and checks its exit status, so any command can be the condition:if grep -q root /etc/passwd; then.
| Numeric | String | File |
|---|---|---|
-eq equal |
= equal |
-e exists |
-ne not equal |
!= not equal |
-f regular file |
-gt greater than |
-z empty |
-d directory |
-ge greater or equal |
-n not empty |
-r / -w / -x readable / writable / executable |
-lt less than |
\< / \> sort order (must be escaped inside [ ]) |
-s exists and isn’t empty |
-le less or equal |
-O / -G owned by you / your group |
|
f1 -nt f2 / f1 -ot f2 newer / older than |
Common trap: -eq compares numbers and = compares strings. Also, < and > inside [ ] are redirection operators unless you escape them.
#!/bin/bash
# compare.sh N1 N2
if [ "$1" -eq "$2" ]; then
echo "Both values are equal"
elif [ "$1" -gt "$2" ]; then
echo "The first value is greater than the second"
else
echo "The first value is less than the second"
fi
- Combine tests with
&&(and) and||(or):if [ -f "$f" ] && [ -r "$f" ]; then. - Bash also has
[[ ... ]], which is safer with empty variables and supports pattern matching ([[ $file == *.log ]]). Use[ ]to match the exam and the book, and know that[[ ]]exists.
case
case compares one value against several patterns. It’s cleaner than a long if/elif chain.
case "$USER" in
rich | barbara)
echo "Welcome, $USER" ;;
testing)
echo "Special testing account" ;;
*)
echo "Sorry, you're not allowed here" ;;
esac
|separates alternative patterns.- Every branch ends with
;;. *)is the catch-all default.- The statement ends with
esac(“case” spelled backward, just asfiendsif). - Patterns use wildcards:
[Yy]*)matches “y”, “Y”, and “yes”.
9. Loops
for
for file in /etc/*.conf; do # a glob is safer than $(ls)
if [ -d "$file" ]; then
echo "$file is a directory"
elif [ -f "$file" ]; then
echo "$file is a file"
fi
done
for n in $(seq 1 2 9); do echo $n; done # 1 3 5 7 9 (start, step, end)
for n in {1..5}; do echo $n; done # brace expansion
for (( i=1; i<=5; i++ )); do echo $i; done # C-style
The book’s example loops over $(ls | sort), which breaks on file names that contain spaces. Loop over a glob (for f in *) instead.
seq takes arguments in the order start, step, end when you give three of them (seq 1 2 9). The book lists them as “start, end, and interval,” which gets the order wrong.
while and until
#!/bin/bash
# factorial.sh N
number=$1
factorial=1
while [ "$number" -gt 0 ]; do
factorial=$(( factorial * number ))
number=$(( number - 1 ))
done
echo "The factorial of $1 is $factorial"
whilerepeats as long as its condition is true.untilrepeats until its condition becomes true.- Always change something inside the loop that eventually makes the condition fail, or the loop runs forever. Press Ctrl+C to stop a runaway loop.
- Read a file line by line with:
while read -r line; do ...; done < file.txt. breakleaves a loop early, andcontinueskips to the next pass.
10. Functions
Functions name a block of code so you can reuse it.
#!/bin/bash
# Two equivalent ways to define a function
function banner {
echo "=============================="
echo " $1"
echo "=============================="
}
log_msg() {
echo "$(date +%T) $*" >> /tmp/script.log
}
banner "Disk report"
df -h /
log_msg "Report generated by $USER"
- Define a function before calling it. Call it by name, like a command.
- Inside a function,
$1,$2, and so on are the function’s arguments, not the script’s. return Nsets the function’s exit status (0–255), which you read in$?. It isn’t meant for returning data. The book’sdblexample returns doubled values throughreturnand breaks for any result above 255.- To return data,
echoit and capture it with command substitution:result=$(dbl 21). local var=valuekeeps a variable private to the function.
dbl() {
echo $(( $1 * 2 ))
}
result=$(dbl 200)
echo "The new value is $result" # 400
11. Background jobs, nohup, and signals
Background mode
$ ./backup.sh &
[1] 19555 # [job number] PID
$ jobs
[1]+ Running ./backup.sh &
...
[1]+ Done ./backup.sh
&runs a command in the background and gives you the prompt back right away.- The job number belongs to this shell. The PID belongs to the whole system.
- Background jobs still write to the terminal. Redirect their output (
> job.log 2>&1 &). - Background jobs are tied to the terminal. When the terminal closes, they get SIGHUP and usually exit.
nohup
$ nohup ./long-task.sh &
nohup: appending output to 'nohup.out'
$ nohup ./long-task.sh > task.log 2>&1 & # better: choose the log file yourself
nohup makes the command ignore SIGHUP, so it keeps running after you log out. If you don’t redirect output, it’s appended to nohup.out in the current directory, so several jobs can mix their output in one file. screen and tmux are alternatives when you need to reattach to a session later.
Signals from the keyboard
| Keys | Signal | Effect |
|---|---|---|
| Ctrl+C | SIGINT (2) | Interrupt: most programs exit |
| Ctrl+Z | SIGTSTP (20) | Stop (pause) the foreground job; it stays in memory |
| Ctrl+D | (not a signal) | End of input (EOF) |
psshows a stopped job with stateT.- If you try to exit with stopped jobs, Bash warns “There are stopped jobs.” Typing
exita second time exits and kills them. kill PIDsends SIGTERM (15), which asks politely.kill -9 PIDsends SIGKILL (9), which can’t be caught or ignored. The book’s job-control listing useskill -9and then describes it as sending SIGHUP; it’s SIGKILL.kill %2sends a signal to job 2 instead of a PID.
12. Job control
$ ./test19.sh
This is a test program 29011
Loop #1
^Z
[1]+ Stopped ./test19.sh
$ ./test19.sh > test19.out &
[2] 28861
$ jobs -l
[1]+ 29011 Stopped ./test19.sh
[2]- 28861 Running ./test19.sh > test19.out &
$ bg 1 # resume job 1 in the background
$ fg 2 # bring job 2 to the foreground
| Command | Action |
|---|---|
jobs |
List this shell’s jobs |
jobs -l / -p |
Include PIDs / show only PIDs |
jobs -r / -s |
Only running / only stopped jobs |
jobs -n |
Only jobs whose status changed since the last report |
bg [%n] |
Resume a stopped job in the background (sends SIGCONT) |
fg [%n] |
Bring a job to the foreground |
+marks the current default job, whichfgandbguse when you don’t give a number.-marks the next job in line. When the+job ends, the-job becomes the default.
13. Scheduling one-time jobs with at
at queues a job to run once at a future time. The atd daemon checks the queue (/var/spool/at or /var/spool/cron/atjobs) about every minute.
$ at -f backup.sh 22:30 # run a script file at 10:30 PM
$ at now + 25 minutes # type commands, then Ctrl+D
at> tar -czf /tmp/etc.tgz /etc
at> <EOT>
$ at 4PM tomorrow -f report.sh
$ atq # list pending jobs: number, time, queue
$ at -c 7 # show what job 7 will run
$ atrm 7 # remove job 7
- Time formats:
10:15,10:15PM,now,noon,midnight,teatime(4 PM), dates likeMMDDYY,MM/DD/YY,DD.MM.YY, orJul 4, and offsets likenow + 25 minutesor10:15 + 7 days. A time that has already passed today means tomorrow. - Output isn’t shown on a terminal. It’s mailed to the user who submitted the job, using the local mail system from Lesson 7.
-msends mail even when there’s no output. - Queues are
a–z.ais the default, and later letters run at lower priority (a higher nice value).batchruns a job when the system load drops. - Jobs run with
/bin/sh(“commands will be executed using /bin/sh”), in the directory and environment where you ranat. - Users can remove only their own jobs.
- Access control:
/etc/at.allow(if it exists, only listed users can useat) and/etc/at.deny. - On systemd systems,
systemd-run --on-calendar=...orsystemd-run --on-active=30mcreates a one-time timer, andsystemctl list-timersshows it.
14. Scheduling recurring jobs with cron
The cron daemon wakes every minute and runs any job whose schedule matches.
Crontab format
# min hour day-of-month month day-of-week command
15 10 * * * /home/rich/bin/report.sh
15 16 * * 1 /home/rich/bin/weekly.sh
0 12 1 * * /home/rich/bin/monthly.sh
*/15 * * * * /usr/local/bin/check-disk.sh
30 2 * * 1-5 /usr/local/bin/backup.sh > /var/log/backup.log 2>&1
| Field | Range |
|---|---|
| Minute | 0–59 |
| Hour | 0–23 |
| Day of month | 1–31 |
| Month | 1–12 or jan–dec |
| Day of week | 0–7 (0 and 7 are both Sunday) or sun–sat |
Field syntax:
*means every value.1-5is a range.1,15is a list.*/15means every 15th value.- Shortcuts include
@reboot,@daily,@hourly,@weekly, and@monthly.
Rules that prevent most cron failures:
- Use full paths for commands and files, because cron’s
PATHis minimal. - Redirect output to a log file, or cron mails it to you.
- The job runs as the crontab’s owner, so that user needs permission to run everything in it.
- Escape
%as\%(for example, inside adate +%F), because cron treats an unescaped%as a newline.
Managing crontabs
$ crontab -l # list your crontab ("no crontab for rich" if none)
$ crontab -e # edit your crontab (uses $EDITOR, often vi or nano)
$ crontab -r # remove your crontab (careful: no confirmation)
$ sudo crontab -u alice -l # root can view or edit another user's crontab
- User crontabs are stored in
/var/spool/cron/(Red Hat) or/var/spool/cron/crontabs/(Debian). Always edit them withcrontab -e, never directly. - System crontabs are
/etc/crontaband the files in/etc/cron.d/. They have an extra user field before the command:0 3 * * * root /usr/local/bin/cleanup.sh. - Periodic directories: scripts placed in
/etc/cron.hourly/,/etc/cron.daily/,/etc/cron.weekly/, or/etc/cron.monthly/run on that schedule. anacron runs missed daily, weekly, and monthly jobs on machines that aren’t always on. - Access control:
/etc/cron.allowand/etc/cron.denywork the same way as theatfiles. - systemd timers are the modern alternative: a
.timerunit triggers a.serviceunit. List them withsystemctl list-timers.
Check for understanding: When does 0 */6 * * 1-5 run? (At minute 0 every six hours, at 00:00, 06:00, 12:00, and 18:00, Monday through Friday.)
15. Putting it together: a complete script
Exercise 9.1 from the book, written defensively:
#!/bin/bash
# pwinfo.sh - display password aging information for every account
# Usage: sudo ./pwinfo.sh
if [ "$(id -u)" -ne 0 ]; then
echo "Run this script with sudo." >&2
exit 1
fi
for user in $(cut -d: -f1 /etc/passwd); do
echo "Password information for $user"
chage -l "$user"
echo "----------"
done
- The shebang selects Bash, and the comment explains the script’s purpose and usage.
- The
ifblock checks for root privileges and exits with status 1 and a message on STDERR if they’re missing. That’s cleaner than runningsudoon every pass through the loop, as the book’s version does. cut -d: -f1extracts the first field (the username) from each line of/etc/passwd(Lesson 7).- The
forloop runschage -lfor each account. The"$user"variable is quoted.
Classroom application
- Variable scope. Set a local variable, start a child shell, and show it’s missing. Export it and repeat. Then set a variable in the child and show the parent can’t see it. Finally, put an alias and an exported variable in
~/.bashrc, and prove they persist in a new terminal. - First script. Write
sysinfo.sh, which prints the host name, date, uptime, disk usage of/, and logged-in users with labeledecholines. Walk through each error students hit on the way (command not found, then permission denied, then success) and explain why each happens. - Arguments and input. Extend the script to take a directory name as
$1(with a usage check on$#) or prompt for one withread -p, then report the directory’s size withdu -sh. - Decisions and loops. Write
filecheck.sh, which loops over the arguments withfor f in "$@"and usescaseoriftests to report whether each is a file, a directory, or missing. Exit with status 1 if any argument was missing. - Job control drill. Run
sleep 300, press Ctrl+Z, runbg, start two more sleeps, then usejobs -l,fg %2, Ctrl+C, andkill %1. Predict which job is the+job at each step. - Scheduling. Schedule a one-time
atjob that writes the date to a file in 2 minutes, confirm it withatq, and read the result. Then add a crontab entry that runs thesysinfo.shscript every weekday at 7:30 AM with its output redirected to a log, and explain each of the five time fields.
Common misconceptions
- “
name = valuesets a variable.” Spaces around=turn it into a command. Writename=value. - “
export $varexports var.” Export the name:export var. - “A script can set variables in my shell.” A script runs in a child shell. Only
source/.runs it in the current shell.execreplaces your shell. - “
.shmakes a file executable.” Execute permission (chmod u+x) and a shebang do that. The extension is only a naming convention. - “
-eqand=are interchangeable.”-eqcompares numbers and=compares strings. - “
[condition]works without spaces.”[is a command, so it needs spaces around it and its arguments. - “
returnsends data back from a function.” It sets an exit status from 0 to 255. Echo the data and capture it with$( ). - “Bash can do decimal math.” It does integer math only. Use
bcfor decimals. - “Background jobs survive logout.” They get SIGHUP when the terminal closes. Use
nohup,screen, ortmux. - “cron uses my normal PATH.” Cron’s environment is minimal. Use full paths and redirect output.
Lesson summary
- Variables: local variables stay in the current shell, while exported (environment) variables are inherited by child processes. Login shells read
/etc/profileand~/.bash_profile, and interactive shells read~/.bashrc. Put aliases and personal settings there. - Building blocks:
;,&&, and||sequence commands.>,>>,2>, and<redirect.|pipes. Quoting and escaping control metacharacters. - Scripts: start with
#!/bin/bash, make the file executable, and run it with./script,bash script, orsource scriptdepending on whether it should run in a child or the current shell. Useecho, variables,$1…$#/"$@",read,exitcodes,$( ), and$(( )). - Logic:
if/test(numeric, string, and file tests),case,for,while/until, and functions (withreturnfor status andechofor data). - Running and controlling:
&,nohup, Ctrl+C (SIGINT), Ctrl+Z (SIGTSTP),kill,jobs,bg, andfg. - Scheduling:
at/atq/atrmfor one-time jobs, andcrontab -ewith the five time fields (plus the system cron directories and systemd timers) for recurring jobs.
The next lesson is Securing Your System.
Course Notes