#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 $ $ $ $ 0
array=(2 1 0) IFS=$'\n' sorted=($(sort <<<"${array[*]}")) unset IFS echo ${sorted[*]} 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$fs\2$fs\3|p" -e "s|^\($s\)\($w\)$s:$s\(.*\)$s\$|\1$fs\2$fs\3|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 " - %s\n" ${!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