The Unbearable Lightness: Extending the Bash shell

Page 1

#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


Turn static files into dynamic content formats.

Create a flipbook
Issuu converts static files into: digital portfolios, online yearbooks, online catalogs, digital photo albums and more. Sign up and create your flipbook.