- In NixOS, the best way to run
#!/bin/bashis to use#!/usr/bin/env bashas shebang $ set- to display a complete list of active environment variables available- User variables
- up to 20 letters/digits/underscores
- case sensitive
- assignments should NOT have spaces at all
var=-10
- stored as text strings by the shell script
- Command substitution
- Two ways:
- the backtick character
- The
$()format
- a subshell is created to run the enclosed command
- a separate child shell
- any variables create in the parent shell will NOT be available to commands in the subshell
- Two ways:
- Subshells are also created if command is run from the CLI using the
./path - Output redirection
command > outputfile>creates the outputfile- overwrites existing file
- use
>>to append (instead of overwrite)
- Input redirection
command < inputfile- e.g.
wc < test1.sh- number of lines, words, and bytes
- inline input redirection
<<- needs a text marker
wc << <marker> - <text> - <marker>
- uses the prompt defined in
$PS2
- Pipes
command1 | command2- both commands are run at the same time
- no intermediate files/buffers are used to transfer the data
- piping operates in real time
- Paging commands:
lessmore
- Math
- Two ways to do math:
exprcommand$ expr 1 + 5- old and NOT recommended anymore
- square brackets
$[operation]- looks like also deprecated
- integer arithmetic ONLY
zshsupports floating-point operations
- use
$((...))
bc- the Bash calculator- supports floating-point solutions
- use
scaleto specify precision (decimal points)- default is
0
- default is
variable=$(echo "options; expression" | bc)- able to do inline input redirection
variable=$(bc << EOF options statements expressions EOF )
- Exiting the script
- every command has an exit status
- exit status: 0 - 255
$?: special variable to grab exit status of the last executed command- needs to be run immediately after
- by default, the script exits with the exit status of the last command in the script
- overwrite that by manually
exit <exit_code> - if
<exit_code>is larger than255, use modulo<exit_code> % 256
- overwrite that by manually
-
if-thenif command # checking if exit status of `command` is zero then commands fi
- alternatively,
if command; then
- alternatively,
-
if-then-elseif command then commands else commands fi
-
if-thencan ONLY evaluate the condition of a command's exit code -
to evaluate other conditions, use
testtest- test whether a variable has content
if test condition then commands fi
-
if [ condition ]- an alternative way to test a condition withouttest- there must be a space after the
[and before the]
- there must be a space after the
-
Numeric comparisons
- bash can only handle integer comparisons
-
String comparisons
- use escaped
\>and\< - otherwise they are interpreted as redirections
- when comparing orders,
\<and\>have different directions thansort sortputs lowercases first
- use escaped
-
if [ -n $string ]- test whether$stringis non-zero in length -
if [ -z $string ]- test whether$stringis zero in length -
-nt/-ot- files newer/older than the other?
- should check whether file exists first
-
Compound testing
if [ condition1 ] && [ condition2 ]if [ condition1 ] || [ condition2 ]
-
Advanced
if-then- Run a command in subshell using
(command) - Math expressions in
((expression)) - Advanced string handling in
[[...]]- allows for pattern matching
- Run a command in subshell using
-
casecase variable in pattern1 | pattern2) commands1;; pattern3) commands2;; *) default commands;; esac
-
forfor var in list # separated by space do commands done
-
IFS- Internal Field Separator- special environment variable
- defines a list of chars used by bash as field separators
- Default field separators:
- a space
- a tab
- a newline
- REMEMBER to reset it afterwards!
IFS.OLD=$IFS IFS=$'\n' ... IFS=$IFS.OLD
- specify more than one character:
IFS="$'\n':;"
-
File globbing
- the process of producing filenames/pathnames that match a specified wildcard
-
C-style
forloopfor (( variable assignment ; condition ; iteration process ))
-
whilewhile test command do other commands done
- terminates when the exit status of
test commandchanges - multiple test commands are allowed -
whileterminates only when the exit status of the last test command changes
- terminates when the exit status of
-
until- opposite of
while - terminates when exit status of test command goes from non-zero to zero
- opposite of
-
breakbreak n- the level of loop to break out of- by default
nis1
-
continuecontinue n
-
Processing the output of a loop
done > output.txtdone < input.txtdone | sort
$0- the script's name- with path
- to use only the script name, use the
basenamecommand$(basename $0)
- up to
$9for the ninth parameter - for more parameters, use
${10},${11}, etc - To test parameters, use
-nif [ -n "$1" ]
$#- number of command-line parametersif [ $# -eq 1 ]${!#}- get the value of the last parameter?CANNOT be used in{}- so it's NOT
${?#}
- To grab all parameters:
$*- all parameters as a single word$@- all parameters as separate words in the same string
shift- moves each parameter variable one position to the left by default
shift <pos>
- use
--to separate options and parameters--indicates end of the option list- note: the parameters have no special relationship with the options
getoptgetopt optstring paramtersoptstring- list of valid option letters- colon
:after the letter which requires a value q- ignore error messages- NOT working well with parameter values with spaces or quotation marks
- use
getopts
- use
- colon
setset --- replace commandline parameter variables with the values specified byset- used with
$@
- used with
getopts- works on existing shell parameter variables sequentially
getopts optstring variable- prepend
optstringwith:to suppress error messages - uses 2 env variables:
OPTARG- parameter valueOPTIND- value of the current location within the parameter list wheregetoptsleft off- incremented by one every time
- bundles any undefined option into a single output,
?
read- either from stdin or file descriptor
- put data read into a variable
- if no variable specified, data stored in the special env variable
REPLY REPLY: contains all data entered in the inputread -pread with a promptread -sin silent mode- no input on display
readfrom a file- a single line of a time
- use
-tto specify a timer - if expired, exit status is non-zero
STDIN-0- overwritten/redirected by
<
- overwritten/redirected by
STDOUT-1- redirected by
>or>>
- redirected by
STDERR-22>- redirectingSTDERRonly1> <file_for_data> 2> <file_for_err>&>- redirect bothSTDERRandSTDOUTto the same file- error messages have a higher priority than stdout
- precede the file descriptor with
&>&2
- To permanently redirect (for the duration of current script) -
execexec 1>testout
execstarts a new shell
exec 0< testinput
- file descriptors
3through8 - redirecting and resetting
STDIN:
exec 6<&0
#...
exec 0<&6- open a single file descriptor for both input and output
exect 3<> testfile- NOTE!
- when reading from and writing to the same file, the shell maintains an internal pointer!
- to close, redirect to
&-exec 3>&-
lsof- list all open file descriptors on the entire Linux systemlsof -p- byPID
$$- currentPID
- redirect to the
nullfile /dev/null- can also be used for input redirection as an input file
- to quickly remove data from an existing file without having to remove the file and re-create it
cat /dev/null > file_to_be_cleared
- can also be used for input redirection as an input file
/tmpfor temp files- auto cleaned up at bootup
mktemp- create a unique temp filemktemp testfile.XXXXXX- by default in the current location
mktemp -t testfile.XXXXXX- create in
/tmp
- create in
mktemp -d dir.XXXXXX- create temp directory
tee- sends data from
STDIN - sends data to both:
STDOUT- a file
- by default overwrites the file
-ato append
- sends data from
- by default
SIGQUITandSIGTERMare ignored by Bash shell- but
SIGHUPandSIGINTare NOT ignored
- but
- when
SIGHUPreceived, before the Bash shell exits, it passes theSIGHUPsignal to any processes started by the shell,- including any running shell scripts
- with
SIGINTsignal, shell is just interrupted- also passed to any processes started by the shell
Ctrl+Cgenerates aSIGINT- To pause the process,
Ctrl+Z- generatesSIGTSTP
- stop vs. terminate - different!
- stoping a process leaves the program in memory
- able to resume where it left off
- stoping a process leaves the program in memory
- to see the list of (stopped) jobs, do
ps -l- state (
S) ofT- either traced or stopped
- state (
- type
exittwice to exit a shell with stopped jobs kill -9 <pid>sendsSIGKILL(9) signal to terminate- Trapping signals
trap <commands> <signals>- watch for
<commands>and intercept them from shell
- To keep critical operations flowing in the script, do:
trap "" SIGINT <other_signals>
- To trap upon script exit
trap <commands> EXIT
- To handle
trapdifferently in various sections in a script- reissue
trapwith new options
- reissue
- To remove a trap
trap -- <list_of_signals><list_of_signals>- list of signals you want to return to default behavior
- To see processes running in the background,
ps -e <command> &- run a command/script in the background- still uses
STDOUTandSTDERRfor messages
- still uses
- background processes started from a terminal session will exit if the session exits
- To keep the script running after the terminal session exits,
nohup <command>- blocks any
SITHUPsignals - NOT associated with the terminal session anymore
- no longer has
STDOUTandSTDERRoutput channels - automatically redirected to
nohup.out
- To see all jobs, run
jobs - To resume the stopped process,
bgandfg- if the default job (with the
+sign) - no need to specify the job id - in Bash,
fg <job_id> - in zsh,
fg %<job_id>
- scheduling priority
- a.k.a. nice value
- the amount of CPU time the kernel assigns to the process relative to other processes
- by default all processes started from the shell have the same priority
-20(highest) <->+19(lowest)
- To set the priority,
nice -n <priority> <command>- by default normal users are NOT allowed to set negative (higher than default) priorities
- only root users can do that
- To change priority of a running process
renice -n <priority> -p <PID>
- Schedule a job
at- specify a future timeat [-f filename] time- submits job to a queue
atd- theatdaemon- runs in background
- checks jobs under
/var/spool/ator/var/spool/cron/atjobs - checks very 60 seconds
- use
-Mto suppress any output generated by jobs
- Job Queue
- 52 queues for different priorities
atoz;AtoZ- by default, jobs submitted to
aqueue -qto specify queue- by default
STDOUT/STDERRare redirected to OS mail system
atq- view pending jobsatrm <job_id>- remove a jobcron- checkscrontables- to run on the last day of every month:
cron 00 12 28-31 * * if [ "$(date +%d -d tomorrow)" = 01 ] ; then <command> ; fi
- to run on the last day of every month:
crontab -l- list an existingcrontable- by default the
crontable does NOT exist for a user
- by default the
crondoes NOT retroactively run missed jobs- to achieve that, use
anacron
- to achieve that, use
anacron- job is guaranteed to run
- ONLY dealing with programs under
crondirectories/etc/cron.monthly/etc/cron.daily/etc/cron.weekly- BUT NOT hourly!
- Uses timestamps to determine if the jobs have been run
- A timestamp file exists for each
crondirectory, located in/var/spool/anacron
- its own table:
/etc/anacrontab
- To run a script every time a new Bash shell is started
- put the scripts in:
$HOME/.bash_profile$HOME/.bash_login$HOME/.profile
- put the scripts in:
function name {
commands
}
# or,
name() {
commands
}- To call a function, just specify the function name on a line
- Redefining a function name will override the original function definition
- Bash shell treats functions like mini-scripts
- with an exit status
- exit status:
- by default, the exit status returned by the last command in the function
$?- check the exit status
- Use
returnto exit the function with a specific exit status- NOTE:
- Remember to retrieve the return value as soon as the function completes
- Remember exit status must be
0-255
- cannot return a string
- NOTE:
- Capture output of a function to a shell variable
result=$(func)
- Passing parameters to function
- inside the function,
$0,$1,$2, etc $0is name of function$#is number of parameters passed to the function - excluding the function itself
- inside the function,
- Parameters passed to the script are NOT the same as those passed to the function within!
- Need to manually pass the parameters to the function!
- Scope of variables
- global by default everywhere
local
- passing the array variable as a function parameter - it would NOT work!
- only the first element of the array will be picked up
- you MUST disassemble the array variable into individual elements!
- use those individual as function parameters
- function uses
echoto output individual array values in the proper order- the script reassembles back into a new array
source- the key- executes commands within the current shell context instead of creating a new shell
- used to run the library file script inside your shell script
- the dot operator - shortcut alias of
source. ./<script>
$ function <func_name> { <command>; }