bash
#define bash: \
I----------------------------------------------------------------\
I----------------------------------------------------------------\
I----------------------------------------------------------------\
I /$$$$$$$ /$$ \
I | $$__ $$ | $$ \
I | $$ \ $$ /$$$$$$ /$$$$$$$| $$$$$$$ \
I | $$$$$$$ |____ $$ /$$_____/| $$__ $$ \
I | $$__ $$ /$$$$$$$| $$$$$$ | $$ \ $$ \
I | $$ \ $$ /$$__ $$ \____ $$| $$ | $$ \
I | $$$$$$$/| $$$$$$$ /$$$$$$$/| $$ | $$ \
I |_______/ \_______/|_______/ |__/ |__/ \
I----------------------------------------------------------------\
I----------------------------------------------------------------\
I----------------------------------------------------------------I
• "Bourne Again SHell"
GNU Readline library : used for all input operations (see AT "C++/Readline\/History")
# high quality introduction
https://mywiki.wooledge.org/BashGuide
# interactive introduction
https://github.com/agvxov/bashtutor
• as bash uses readline for input, all readline shortcuts apply (in theory however
terminal emulators may have confronting bindings) (see AT "C++/Readline\/History")
bash [options] : launches interactive bash session
— f : disable globing (see AT "./Globs")
--noprofile : ignore bash profile files (/etc/profile, ~/.bash_profile, ~/.bash_login, ~/.profile)
--norc : ignore bashrc files (~/.bashrc)
Files: Files:
.bashrc : where settings and preferences are read from
.bash_profile : where strictly interactive shell settings and preferences are read from
.bash_history : where command history is stored
.bash_logout : where commands to be executed on log out are read from
Builtins: Builtins:
• features which behave like programs
• they are faster than using real programs, because there is no fork involved
• there is no technical guarantee regarding the availability of builtins,
however they dont change much and you may list them with "compgen -b"
• see controlling builtins under enable, BELOW
. [file] : execute bash script [file], in the current shell
$ bat example.sh
───────┬───────────────────
│ File: example.sh
───────┼───────────────────
1 │ goo="nar"
───────┴───────────────────
$ ./example.sh
$echo ${goo}
$ . ./example.sh
$ echo ${goo}
nar
: : null command; does nothing; its exit status is always success
[ ]
alias : lists defined aliases
alias [name]="[command]" : creates alias
unalias [name] : deletes alias
• to add a permanent alias one must specify it in a config file {".bashrc"} (see AT "/Bash/Files")
• [alias] [...] will append [...] to the called command as argument(s)
• to never use an alias or alternatively put, escape it, one can prefix any bash command with a '\\' char
$ alias pwd="echo Dunno mate, somewhere..."
$ pwd
Dunno mate, somewhere...
$ \pwd
/home/user
bg : see AT /Linux/Processes
bind : sets readline keybinding from the command line
break : exits the current loop
builtin [builtin] [args] : executes [builtin] with [args] passed;
never does a binary lookup
caller
cd [folder] : changes directory
command
compgen
complete
compopt
continue
declare [options] [var declaration] : declares var with special traits
• use a '+' to instead remove an attribute from a var (yes, yes really)
— a : array
— f : function name
— i : int
— r : read only
— x : export; make global
dirs : prints directory stack; see AT ../Directory_stack
disown : disown (separate; make independent of) a program from the shell; use with '&'
{mousepad & disown}
echo <string> : echoes <string> back
enable [options] : controls builtins
— a || -p : prints all builtins
— n [builtin] : disables [builtin]
— s : prints POSIX "special" builtins
— f [file] : load builtin
— d [builtin] : unload builtin [builtin] loaded with -f
eval <string> : evaluates <string> as a bash command
exec
exit
export
false
fc
fg : foreground; brings background process to the foreground
getopts <string> [name] : utility for easy option parsing;
stores parsed options in [name];
<string> is a not separated list of expected options;
options expecting a meta option shall have a ':' after them;
meant to be used in a while loop;
saves progress index into ${OPTIND};
if calling getopts multiple times is desired ${OPTIND} must be manuali reset to 1
saves the meta option to ${OPTARG}
while getopts "hvo:" MYVAR; do // please ignore the '(' at the start of the lines
case "$MYVAR" in
h) my_help ;;
v) my_version ;;
o) my_option=${OPTARG} ;;
esac
done
hash
help : display information about builtins
history
jobs
kill
let
local
logout
mapfile
popd : pops directory stack; see more AT ../Directory_stack
printf
pushd : pushes a path to the directory stack; see more AT ../Directory_stack
pwd
read [options] [var] : reads a line and stores it in [var]
— r : do not allow backslashes to escape any chars
readarray
readonly [var-name] : makes [var-name] readonly (const); [name] must be assigned after hand
return
set
shift <int> : shift positional parameters;
rename the positional parameters $<int>+1,$<int>+2... to $1,$2... if <int> is
not given, it is assumed to be 1
shopt : "SHell OPTion"; controls internal bash options
source [FILE] : alias of '.'; see ABOVE
suspend
test
times
trap
true
type
typeset
ulimit
umask
unalias
unset [var-name] : delete-s [var-name]; [var-name] is only the name, no '$' is needed;
readonly variables cannot be unset
{ $ MYVAR="my value"
$ echo $MYVAR
my value
$ unset MYVAR
$ echo $MYVAR
$
}
wait
Globs: Globs:
• sometimes also called wildcards
• used for matching patterns
• do not match hidden files (see AT ./Glob_related_options)
• can be escaped { \* }
? : any (one) char
* : any or none chars
[(!||^)[...]||[keyword]] : a list of chars from which one is to be matched { [02468] };
'!' and '^' signal negation { [!a] -> "not 'a'" }
• case sensitive
• '-' can be used to symbolize a range { [0-9] } { [a-z] } { [A-Z] }
[keyword]:
[:alnum:] : any alphanumeric char
[:space:] : any whitespace char
[:digit:] : any digit char, '_' or '.'
Extended_globs:
• turned off by default
shopt -s extglob
• can be nested
[specifier]([pattern](|pattern[|[...]]))
[specifier]:
? : matches zero or one occurrences of the patterns
* : matches zero or more occurrences of the patterns
+ : matches one or more occurrences of the patterns
@ : matches occurrences of atleast one of the patterns
! : matches anything not containing any of the patterns
[pattern]:
• string { ls @(M|S)* -> all files starting with an 'M' or 'S' }
• not necessary, but sometimes a glob expression (particularly in '!' expressions) { ls !(*.jpg|*.gif) -> all non-jpgs and non-gifs}
{ ls !(*Megadeth*|*01.*) -> lists all albums (presuming a nice and orderly naming of them) except the
the first ones of a band and the ones made by Megadeth }
Glob_related_option:
extglob : see ABOVE
nullglob : expands non-matching glob extension to an empty string rather then itself
dotglob : makes the '*' glob match hidden files too, but not .. or .
globstar : makes "**" match all files and folders recursively; "**/" will only match folders
failglob : reports an expansion error if no matches are found
Directory_stack: Directory_stack:
• a container of stored directories
• for fast and easy directory manouvering
• the directory on the top of the stack is always the current working directory
• the stack is 0 indexed
(>all following commands are builtins) (
dirs : prints directory stack
pushd ([path]) ([num]) : pushes [path] to the top of the stack; if no [path] is supplied, swaps the top two directories;
[num] is an index to bring forward other stack members
popd ([num]) : removes the [num] indexed directory from the stack; if no [num] is supplied, the top is defaulted
SCRIPTING: SCRIPTING:
#!/bin/bash
• you are obviously gonna be using bash commands and variables
Comments: Comments:
#[comment] : single line
• multi line comments are feasible, but not intended; just use '#'
Variables: Variables:
• every variable behaves as a string being copy pasted left and right
○ list of builtins which manipulate variables
• readonly
• unset
[name]=[value] : assign variable a variable; do not use whitespaces
$[name] || ${[name]} : reference an already declared variable
• it is recommended to use curly braces whenever referencing one ( ${[name]} ),
otherwise it might be subject to word splitting
{ $ MYVAR="some value"
$ echo ${MYVAR}
some value
}
${#[name]} : expands to the length of [name]
Strings:
• 0 indexed
${[name]:} : expands to ${[name]} from the <int>th char until the end
${[name]:[int-1]:[int-2]} : expands to ${[name]} from the [int-1]th char until the [int-2]th char
Arrays:
• always 1 dimensional
Indexable:
• not required to be continuous
• every unassigned position will return an empty string
[name]=([values]) : declares and assigns an array; [values] is a ${IFS} separated list of strings
[name]<int>=[value] : declares an array and assigns a single, arbitrary index of it
[name]+=([values]) : concatenates [values] to an array
$[array-name] : expands to the first member of [array-name]
${[array-name][]} : expands to the <int>th member of [array-name]
${[array-name][*]} : expands to every member of the array separated by the first char of ${IFS}
Associative:
pass
Default: Default:
• otherwise called keyword variables
<int> : argument(/positional parameter) number <int>; between 1-9, to access later arguments see AT "../Builtins/shift";
0 is always the scripts name
@ : array of arguments(/positional parameters) (starting from one);
for POSIX compliance reasons it expands to all elements instead of just the first
* : ${@}, BUT when used between quotes it uses ${IFS} (see BELOW) to separate them on return
# : number of arguments(/positional parameters) (-1)
$ : process id of the shell
! : process id of the most recently executed background process
? : return value of the most recently executed program
— : set builtin command?!
_ : last argument to the previous command; at shell startup, set to the absolute pathname
auto_resume : if set to 1, the last background process can be brought to the foreground without a preceding '%'
BASH : the full path to file used to invoke current bash instance { /bin/bash }
BASH_ALIASES : array of all bash aliases
BASH_ARGC : array of all stack frame argument counts; XXX: shopt -s extdebug
BASH_ARGV : array of all stack frame arguments; XXX: shopt -s extdebug
BASH_ARGV0 : $0 (see ABOVE)
BASH_CMDS : ?!
BASH_COMMAND : the command currently being executed or about to be executed
BASH_COMPAT : ?!
BASH_LINENO : ?!
BASHOPT : a colon-separated list of enabled shell options
BASHPID : the process id of current bash instance
BASH_REMATCH : ?!
BASH_SOURCE : ?!
BASH_SUBSHELL : ?!
BASH_VERSINFO : array whose members hold version information about this bash instance
0 : release number
1 : version number
2 : patch level
3 : build level
4 : release status
5 : value of MACHTYPE (?!)
BASH_VERSION : a string representing the version of the version of the instance of bash
BASH_XTRACTEFD : ?!
CDPATH : a colon separated list of directories which will be searched by cd for subdirector before . is
CHILD_MAX : ?!
COLUMNS : number of available columns to print to (width in chars)
COMP_CWORD : ?!
COMP_KEY : ?!
COMP_POINT : ?!
COMPRELY : ?!
COMP_TYPE : ?!
COMP_WORDBREAKS : ?!
COMP_WORDS : ?!
COPROC : ?!
DIRSTACK : ?!
EMACS : ?!
ENV : ?!
EPOCHREALTIME : the number of seconds since epoch as a float
EPOCHSECONDS : expands to the number of seconds since epoch
EUID : expands to the used ID of the current user
FCEDIT : ?!
FIGNORE : colon separated list of suffixes to never auto complete files possessing them
FUNCNAME : ?!
FUNCNEST : maximum function nesting, surpassing this value will result in an abort; its for excaping infinite recursiveness
GLOBIGNORE : colon separated list of patterns to never match paths possessing them with globs
GROUPS : array whose members are the groups the current user is a member of
histchars : ?!
HISTCMD : ?!
HISTCONTROL : colon separated list of options to be used on saving the history
ignorespace : dont save lines beginning with a space
ignoredups : dont save lines matching the previous one
ignoreboth : short for ignorespace:ignoredubs
erasedups : remove all lines matching the current one before saving
HISTFILE : the file to be used for saving history
HISTSIZE : number of commands to remember; set to 0 to disable history; set to a negative number to make it unlimited
HISTTIMEFORMAT : format string to mark the time of execution
HOME : the home directory of the current user
HOSTFILESIZE : maximum number of lines in $HISTFILE
HOSTFILE : the file that contains hostnames that the shell might need to complete
HOSTIGNORE : colon separated list of patterns to ignore commands on save
HOSTNAME : the host's name {kali}
HOSTTYPE : the host's type {x86_64}
IFS : Internal Field Separator; expands to space, tab and newline; { ls$IFS-l }
IGNOREEOF : number of consecutive EOF signals ([ctrl] + [d]) to be required before exiting the shell
INPUTRC : ?!
LANG : locale
LC_ALL : ?!
LC_COLLATE : ?!
LC_CTYPE : ?!
LC_MESSAGES : ?!
LC_NUMERIC : ?!
LINENO : the line where its referenced if in a script, otherwise no meaning is guaranteed, but seems to be the number of the commands run from the bash instance
LINES : number of lines of the console
MACHTYPE : "[CPU]-[manufacturer]-[system]" ($HOSTTYPE-[manufacturer]-$OSTYPE) {x86_64-pc-linux-gnu}
MAILCHECK : specifies how often to check for mail in seconds
MAILPATH : colon separated list of file names to be checked for mail
MAPFILE : ?!
OLDPWD : the previous working directory
OPTARG : ?!
OPTERR : ?!
OPTIND : ?!
OSTYPE : operating system type {linux-gnu}
PATH : colon separated list of directories to search for commands
PIPESTATUS : ?!
POSIXLY_CORRECT : ?!
PPID : Parents Process ID
PROMPT_COMMAND : ?!
PROMPT_DIRTRIM : ?!
PS0 : "Prompt String 0"; displayed before output messages of programs
PS1 : "Prompt String 1"; the string which is displayed before the shell takes a command
PS2 : "Prompt String 2"; displayed whenever the shell continues to take commands after a command {multi lines; bash statements {if}}
PS3 : "Prompt String 3"; displayed inside select (builtin) loops
PS4 : ?!
PWD : the working directory
RANDOM : a random number between 0 and 32767
READLINE_LINE : ?!
READLINE_POINT : ?!
REPLY : ?!
SECONDS : number of seconds since the current shell was invoked
SHELL : full path name of the shell
SHELLOPTS : colon separated list of enable shell options
SHLVL : Shell Level; number of bash instances running on top of each other
SRANDOM : a 32 bit random number
TIMEFORMAT : ?!
TMOUT : ?!
TMPDIR : name of the directory where bash shall place temporary files
UID : User ID
Execution: Execution:
[cmd-1] [operator] [cmd-2]
• by placing operatirs between individual commands the nature of there execution can be altered
Sequentual:
• usual behaviour
• each command in the line waits for the previous to finish execution
Pure:
operator: ;
• experienced through the commandlines basic usage
• implicitly invoked when a new line is encountered and a builtin doesnt override the behaviour
• explicit-ly invoked by a semi-colon
{
sleep 10; echo "Done"
}
And:
operator: &&
• only execute the second command if the first one exited successfully
{
grep 'a' my_file.txt && cat my_file.txt
}
• notice how its behaviour is best explained from the perspective of execution,
but its perfectly equivalent to a logical and operator
{
read EXAMPLEVAR
[ "$EXAMPLEVAR" == "test" ] && echo "True"
read EXAMPLEVAR
if (( 10 < $EXAMPLEVAR )) && (( $EXAMPLEVAR < 100 )); then
echo "It is."
fi
}
Or:
operator: ||
• only execute the second command if the first one exit value indicates failure
{
grep 'a' my_file.txt || cat my_file.txt
}
• notice how its behaviour is best explained from the perspective of execution,
but its perfectly equivalent to a logical or operator with short circuiting
{
read EXAMPLEVAR
[ "$EXAMPLEVAR" == "test" ] || echo "True"
read EXAMPLEVAR
if (( $EXAMPLEVAR < 100 )) || (( 200 < $EXAMPLEVAR )); then
echo "It is."
fi
}
Paralel:
• run multiple commands at the same time
• do not wait for finish
Pure:
operator: &
• closest thing Bash has to multithreading
{
#
function my_fun1(){
for i in $(seq 1 1 100); do
echo $i
done
}
#
function my_fun2(){
for i in $(seq 100 1 200); do
echo $i
done
}
#
my_fun1 & my_fun2
}
• can be used during interactive usage to "put something to the background" (obviously stdout wont just magically disappier)
Pipe:
operator: |
• by far the most powerful feature of Bash
• hooks the first commands stdout to the seconds stdin creating a chain of sorts
• all common pajeet "tutorials" fail to mention that the two commands run simultaneously
Operators: Operators:
var:
${/[str1]/[str2]]} : replaces first occurrences of [str1] with [str2]; do not prefix [variable] with a '$'
${//[str1]/[str2]]} : replaces all occurrences of [str1] with [str2]; do not prefix [variable] with a '$'
${#} : expands to string length
${#[regex]} : expands to <string> with the shortest match of [regex] deleted from the beginning
${##[regex]} : expands to <string> with the longest match of [regex] deleted from the beginning
${%[regex]} : expands to <string> with the shortest match of [regex] deleted from the end
${%%[regex]} : expands to <string> with the longest match of [regex] deleted from the end
Logic: Logic:
spaces mater hardcore
Comparison_operators:
{
if [condition]; then
[...]
(elif [condition]; then
[...])
(else
[...])
fi
}
[condition]:
• if tests the exit value of [condition]
• bash provides many builtins with versatile operators to ease writing conditions
• to deploy logic between conditions one must deploy builtin sequential execution operator-s (see AT "../Execution/Sequentual")
Builtin!:
! [condition]
• performs logical not on the [condition] to its right
Builtin[]:
[ [operator] ]
• whitespace sensitive
if [ $1 == "-h" ]; then
show_my_help_message
fi
# ---
[ -v myvar ] || myvar="default"
Strings:
[string-1] == [string-2] : equals
[string-1] != [string-2] : not equals
[string-1] =~ [string-2] : regex equals
[string-1] > [string-2] : greater than
[string-1] < [string-2] : less than
[string-1] >= [string-2] : greater than or equal to
[string-1] <= [string-2] : less then or equal to
— n <string> : is not null (ie. not empty)
— z <string> : is null (ie. empty)
Integers:
[int-1] -eq [int-2] : equals
[int-1] -ne [int-2] : not equals
[int-1] -gt [int-2] : greater than
[int-1] -lt [int-2] : less than
[int-1] -ge [int-2] : greater than or equal to
[int-1] -le [int-2] : less than or equal to
FILE:
— d [path] : is directory path
— e [path] : is existing path
— s [path] : is not an empty file
— O [path] : is owned by ${USER}
— r [path] : is readable by ${USER}
Misc:
— v [var] : is set
Builtin(()):
(( [operator] ))
• whitespace sensitive
{
if (( $1 > 100 )); then
show_my_error_message
fi
}
[int-1] == [int-2] : equals
[int-1] != [int-2] : not equals
[int-1] > [int-2] : greater than
[int-1] < [int-2] : less than
[int-1] >= [int-2] : greater than or equal to
[int-1] <= [int-2] : less then or equal to
Loops: Loops:
While:
{ while [condition]
do
[...]
done
}
Until:
{ until [condition]
do
[...]
done
}
• opposite of while; runs while condition is false
For:
{ for (([initialize var]; [condition]; [increment]))
do
[...]
done
}
• pay special attention to the braces
For_each:
{ for [var] in [list]
do
[...]
done
}
(>[list] can be an array or files)
• for gods sake, do not do { for i in ${ls .} };
do { for i in * } instead!
Select:
• intended for easy interactive menus
• enum-s a [list] of options and takes input repeatedly
• invalid input is discarded
• ints in the enum range are accepted
• a given var-s value is set to the chosen option
• break/continue applies
{ select [var] in [list]
do
[...]
done
}
break
continue
Functions: Functions:
{ (function) [name]() {
[code]
(return ([value]))
}
}
• the keyword "function" is optional, however if ones aiming for compatibility with other shells,
its best to NOT use it, but using it could prevent collisions with alias-es
○ calling
[name] (arguments)
Redirections: Redirections:
[command] < [file] : places [file]s contents to [command]s stdin
[command] [source][mode] [file] : redirects specified outputs of [command] to [file]
[source]:
• || 1> : stdout
2> : stderr
&> : stdout and stderr
[mode]:
[none] : overwrite
| : overwrite even if noclobber is set
• : append
{ echo "asd" >> ./my_file.log }
![...] : runs a command from the command history
! : previous command; useful for running a command again with sudo {sudo !!}
[num] : [num]th command from history
— [num] : relative position in command history; -1 being the previous command
<string> : most recent command from history STARTING with <string>
?<string>? : most recent command from history CONTAINING <string>
# : the current command, from beging till itself { printf !# -> printf printf -> "printf" printed}
$ : last argument of the last command
{[...]} : clarifies that only the text between the curly braces are meant to be interpreted
{ echo Vera; {!-1}nda; the ';' is not literal, commands executed in the same line are
written to the history file at the same time therefore literal "; {!-1}" will result in
non-sense}
Jobs: Jobs:
• the concept of jobs only exists on the shell level;
it is an abstraction, it has no real kernel-wise representation
• every process invoked interactively is a job
• jobs are bound to the invoking shell instance and therefor do not overlive it
• the job blocks the shell for reprompting is said to be running in the foreground
• the job(s) which do not run in the foreground are said to be running in the background
• both foreground and background jobs stdout and stderr outputs are displayed in terminal (if not redirected)
• jobs run in the foreground by default
[cmd] & : invokes a process in the background; '&' is just the pure parallel execution operator
without a second argument, see "/Bash/Execution/Paralel/Pure"
jobs : lists background jobs;
'+' marks the default job
'-' marks the reserve job, which will become the default that terminates
bg ([job]) : makes previously stopped job [job] resume execution in the background; if [job] is not specified the default is used
fg ([job]) : moves [job] to the foreground; if [job] is not specified the default is used
[job]:
%<int> : by id
%+ : default job
%- : reserve job
### Jobs in Bash ### #₩
# this operation takes a considerably long time to finish
$ find / -iname '*a*' &> files_with_a_in_their_names.list
# long long thinking
$
# however, by running it in the background,
# we don't have to wait before we can run another command from the same shell
$ find / -iname '*a*' &> files_with_a_in_their_names.list &
$
moving a job from the background to the foreground
# start a few jobs so we have a few options to choose from
$ find / -iname '*a*' &> files_with_a_in_their_names.list &
$ find / -iname '*b*' &> files_with_b_in_their_names.list &
$ find / -iname '*c*' &> files_with_c_in_their_names.list &
$ find / -iname '*d*' &> files_with_d_in_their_names.list &
[1] 17156
[2] 17157
[3] 17158
[4] 17159
# listing the background jobs because in this example
# I'm a goldfish with a very small terminal
$ jobs
[1] Running find / -iname '*a*' &> files_with_a_in_their_names.list &
[2] Running find / -iname '*b*' &> files_with_b_in_their_names.list &
[3]- Running find / -iname '*c*' &> files_with_c_in_their_names.list &
[4]+ Running find / -iname '*d*' &> files_with_d_in_their_names.list &
# bring the 3th one into the foreground
$ fg %3
moving a job from the foreground to the background
# start in the foreground
$ find / -iname '*a*' &> files_with_a_in_their_names.list
# stopping it explicitly
# Yellow( Ctrl+z ) key combination hit
^Z
[1]+ Stopped find / -iname '*a*' > files_with_a_in_their_names.list
# resume in the background
$ bg %1
#