KEMBAR78
The Unbearable Lightness: Extending the Bash shell | PDF
#LinuxDay2016
http://lugroma3.org/
The Unbearable
Lightness
Extending the Bash shell
I have a natural revulsion to any operating system that
shows so little planning as to have named all of its
commands after digestive noises (awk, grep, fsck, nroff).
Source: The UNIX HATERS Handbook
Shellshocks
CVE-2014-6271
env x='() { :;}; echo vulnerable' bash -c "echo this is a test"
CVE-2014-7169
env X='() { (a)=>' bash -c "echo date"; cat echo
Weaknesses
http://mywiki.wooledge.org/BashWeaknesses
Speed
It's too big and too slow.
Source: man bash
Everything is text
egrep '^To:|^Cc:' /var/spool/mail/$USER | 
cut -c5- | 
awk '{ for (i = 1; i <= NF; i++) print $i }' | 
sed 's/,//g' | grep -v $USER | sort | uniq
Floating point
$ echo $((3/2))
1
Multidimensional
arrays
$ array=('d1=(v1 v2 v3)' 'd2=(v1 v2 v3)')
$ for elt in "${array[@]}";do eval $elt;done
$ echo "d1 ${#d1[@]} ${d1[@]}"
$ echo "d2 ${#d2[@]} ${d2[@]}"
Sorting
$ array=(2 1 0)
$ IFS=$'n' sorted=($(sort <<<"${array[*]}"))
$ unset IFS
$ echo ${sorted[*]}
0 1 2
Variable typing
$ declare -i x
$ x=foo
$ echo $x
0
Variable scope
Local vs Global vs Environment
Return values
Bash functions don't return anything (except numbers in the
range 0-255); they only produce output streams
Passing by
reference
function swap()
{
eval "$1=${!2} $2=${!1}"
}
$ x=a y=b
$ swap x y
b a
Function scope
$ shopt -s extdebug
$ function foo() { echo $qux ; echo ${BASH_ARGV[0]} ; }
$ function bar() { local qux=thud ; foo ; }
$bar baz
thud
baz
Function collapsing
chatter() {
if [[ $verbose ]]; then
chatter() {
echo "$@"
}
chatter "$@"
else
chatter() {
:
}
fi
}
No closures
No first-order functions, no lambdas, ...
Try/catch
trap
Exception handling
set -e
Process
management
select? poll? events?
Parsing
sed 
-ne "s|^($s):|1|" 
-e "s|^($s)($w)$s:$s["'](.*)["']$s$|1$fs2$fs3|p" 
-e "s|^($s)($w)$s:$s(.*)$s$|1$fs2$fs3|p"
Binary data
dd if=/dev/brain of=/dev/null
Paradigms
OO? Functional? Flow-driven? Reflective?
Security
Did you say dropping permissions?
Large programs
source foobar.sh
Debugging
set -x
Subshell Dilemma
$ c=0; ls * | while read i; do ((c++)); done; echo $c
0
Bashisms
eval x=$$x
Portability
It is easier to port a shell than a shell script.
Source: Larry Wall
Why does it
matter?
DRY
Don't write scripts, write libraries
DevOps
Python/Ruby/Scala/... are not ubiquitous
Legacy code
Attempts
bang.sh
the "b" namespace
bashinator
function createDirectory() {
local directory=${1}
if [[ -z "${directory}" ]]; then
__msg err "argument 1 (directory) missing"
return 2
fi
__msg debug "directory: ${directory}"
if ! mkdir -p "${directory}" >> "$_{L}" 2>&1; then
__msg err "failed to create directory '${directory}'"
return 2
fi
return 0
}
bash automated
testing system
@test "addition using bc" {
result="$(echo 2+2 | bc)"
[ "$result" -eq 4 ]
}
@test "addition using dc" {
result="$(echo 2 2+p | dc)"
[ "$result" -eq 4 ]
}
bash infinity
import util/namedParameters util/class
class:Human() {
public string name
public integer height
public array eaten
Human.__getter__() {
echo "I'm a human called $(this name), $(this height) cm tall."
}
...
}
bash manager
hello:
p1=World!
$ ./bash_manager.sh -h /tmp/helloHome
Hello World!
bash toolbox
alias fail='printf "${BASH_SOURCE##*/}: ${FU ...
alias debug='printf "${BASH_SOURCE##*/}: ${FU ...
alias caller='nm=$(builtin caller 0); nm=${nm% ...
bashworks
Inversion of control: the overall program's flow of control
is not dictated by the caller, but by the framework.
Polite functions: Generic reuseable functions usually take a
module name string argument.
blp
minimalist approach
log4sh
# set alternative 'nc' command
log4sh_setAlternative nc /bin/nc
# add and configure a SyslogAppender that logs to a remote host
logger_addAppender mySyslog
appender_setType mySyslog SyslogAppender
appender_syslog_setFacility mySyslog local4
appender_syslog_setHost mySyslog somehost
appender_activateOptions mySyslog
# say Hello to the world
logger_info 'Hello, world'
mbfl
mbfl_argv_all_files || 
exit_because_wrong_command_line_arguments
for item in "${ARGV[@]}"
do
test "${script_option_AUTO}" = yes && {
size=$(mbfl_file_get_size "${item}")
...
oobash
## class Dialog
Dialog=(
# Explicit definition is needed to make inheritance possible.
function __new__ = Dialog::__new__
function __delete__ = Dialog::__delete__
)
ticktick
. ticktick.sh
function printEmployees() {
for employee in ``people.Engineering.items()``; do
printf " - %sn" ${!employee}
done
}
Bashlets
Modular
source bashlet datatype/version
bash$$ version sort 1.44 1.4 1.4.4 1.4.4a 1.4-1234
Git integration
General-purpose
IPC, math, network, OS-abstraction, parsers, UX, ...
Extensible
Plugins for web protocols, databases, RCS, ...
Smart autoloading
Via introspection
Work in progress
Colophon
vim, Hovercraft!, CentOS Linux 7.2
exit 0
Roberto Reale
https://bashlets.sh
https://github.com/bashlets

The Unbearable Lightness: Extending the Bash shell