SlideShare a Scribd company logo
Don’t BASH your head in:
Rx for shell variables.
Steven Lembark
Workhorse Computing
lembark@wrkhors.com
Quick review
BASH is interpreted.
Loops are re-parsed.
Variables can appear anywhere.
Unlike Perl, Python, Ruby, Go, Haskell, Scala, Scheme,
Which separate statements from var’s.
Basic Variables
Assignments to foo:
foo=’$files’; literal ‘$files’.
Basic Variables
Assignments to foo:
foo=’$files’; literal ‘$files’.
foo=”$files”; interpolated value of files.
Basic Variables
Assignments to foo:
foo=’$files’; literal ‘$files’.
foo=”$files”; interpolated value of files.
foo=$(ls $files); command output.
Basic Variables
Assignments to foo:
foo=’$files’; literal ‘$files’.
foo=”$files”; interpolated value of files.
foo=$(ls $files); command output.
foo=”$(ls $files)”; string with listing of files.
Basic Variables
Assignments to foo:
foo=’$files’; literal ‘$files’.
foo=”$files”; interpolated value of files.
foo=$(ls $files); command output.
Most of the work is interpolating:
echo “Your files are: $(ls $somedir)”;
De-mangling variable names
> foo=’bar’;
> echo “foo$foo”; ”foobar”
> echo “$bar_foo”; “”
Oops: Variable “bar_foo” doesn’t exist.
De-mangling variable names
> foo=’bar’;
> echo “foo$foo”; ”foobar”
> echo “$bar_foo”; “”
Isolate ‘foo’ as variable name:
“${foo}_bar # “bar_bar”
Variable commands
cmd=’/bin/ls’;
arg=’-lt’;
Variable commands
cmd=’/bin/ls’;
arg=’-lt’;
files=$($cmd $arg $1); /bin/ls -lt ...
Variable commands
# interpolate each command into the loop
for i in $cmd1 $cmd2 $cmd3
do
$i $args;
done
Really anywhere!
foo=’bar’;
Really, anywhere!
foo=’bar’;
$foo=’blort’;
Q: What happens?
Really, anywhere!
foo=’bar’;
$foo=’blort’;
Q: What happens?
A: Nada.
bash: bar=blort: command not found
Your one chance at success
BASH parses in two phases:
Lexical substitution & tokenizing.
Execution.
Variables have to expand on the first pass to be used.
“foo=blort” cannot be executed, so it failed.
A second chance in life
‘eval’ adds one cycle.
Interpolates variables.
Passes result to the shell.
‘++’ is two levels deep.
> eval"$foo=blort";
+ eval bar=blort
++ bar=blort
> echo $bar;
+ echo blort
blort
Or a third chance...
eval “eval … “;
Work out what is happening:
a=’$HOME/?.*’;
b=’foo’;
c=eval “eval $a $b”’;
Verbosity & Execution
See what bash is doing with the variables:
> set -vx;
Verbosity & Execution
See what bash is doing with the variables:
> set -vx;
echo -ne "033]0;./$(basename $PWD) 007"
+++ basename
/sandbox/lembark/writings/RockfordLUG/bash
++ echo -ne '033]0;./bash 007'
>
Verbosity & Execution
See what bash is doing with the variables:
> set -vx;
echo -ne "033]0;./$(basename $PWD) 007"
+++ basename
/sandbox/lembark/writings/RockfordLUG/bash
++ echo -ne '033]0;./bash 007'
>
“unset” removes variables
> unset PROMPT_COMMAND;
> set -vx;
>
Or set verbosity in the script
#!/bin/bash -vx
…
or localize the verbosity:
set -vx;
do something
set -;
Verbosity & Execution
> unset PROMPT_COMMAND;
> set -vx;
> foo=bar; what I typed
foo=bar; what BASH read
+ foo=bar single ‘+’is one level deep
Verbosity & Execution
> unset PROMPT_COMMAND;
> set -vx;
> foo=bar; what I typed
foo=bar; what BASH read
+ foo=bar single ‘+’is one level deep
> $foo='blort';
>foo='blort';
+ bar=blort no second chance to re-parse
Verbosity & Execution
> unset PROMPT_COMMAND;
> set -vx;
> foo=bar; what I typed
foo=bar; what BASH read
+ foo=bar single ‘+’is one level deep
> $foo='blort';
>foo='blort';
+ bar=blort no second chance to re-parse
bash: bar=blort: command not found
Why use ‘-vx’?
-v alone is useful sometimes.
-x alone usually isn’t.
Example: Hidden disk hogs
#!/bin/bash
dirs="/home/$(whoami)/.*";
cmd="du -msx $dirs | sort -rn | head -3";
eval "$cmd";
Buggy hogs
$ ./y
1232 /home/lembark/.
0 /home/lembark/..
Add verbosity
#!/bin/bash
set -vx;
dirs="/home/$(whoami)/.*";
cmd="du -msx $dirs | sort -rn | head -3";
eval "$cmd";
Shows the bug: . & ..
$ ./y
dirs="/home/$(whoami)/.*";
++ whoami
+ dirs='/home/lembark/.*'
cmd="du -msx $dirs | sort -rn | head -3";
+ cmd='du -msx /home/lembark/.* | sort -rn | head -3'
eval "$cmd";
+ eval 'du -msx /home/lembark/.* | sort -rn | head -3'
du -msx /home/lembark/.* | sort -rn | head -3
++ sort -rn
++ head -3
++ du -msx /home/lembark/. /home/lembark/..
/home/lembark/.aceinnovative /home/lembark/.adobe <snip>
1232 /home/lembark/.
0 /home/lembark/..
Fix: Add a letter
#!/bin/bash
set -vx;
dirs="/home/$(whoami)/.[a-z]*";
cmd="du -msx $dirs | sort -rn | head -3";
eval "$cmd";
Start with the right dirs
$ ./y
dirs="/home/$(whoami)/.[a-z]*";
++ whoami
+ dirs='/home/lembark/.[a-z]*'
cmd="du -msx $dirs | sort -rn | head -3";
+ cmd='du -msx /home/lembark/.[a-z]* | sort -rn | head -3'
eval "$cmd";
+ eval 'du -msx /home/lembark/.[a-z]* | sort -rn | head -3'
du -msx /home/lembark/.[a-z]* | sort -rn | head -3
++ sort -rn
++ head -3
++ du -msx /home/lembark/.aceinnovative /home/lembark/.adobe
<snip>
270 /home/lembark/.openoffice
244 /home/lembark/.mozilla
193 /home/lembark/.config
Compare: Only “-v”
$ ./y
dirs="/home/$(whoami)/.[a-z]*";
cmd="du -msx $dirs | sort -rn | head -3";
eval "$cmd";
du -msx /home/lembark/.[a-z]* | sort -rn | head -3
270 /home/lembark/.openoffice
244 /home/lembark/.mozilla
193 /home/lembark/.config
Compare: Only “-x”
$ ./y
++ whoami
+ dirs='/home/lembark/.[a-z]*'
+ cmd='du -msx /home/lembark/.[a-z]* | sort -rn | head -3'
+ eval 'du -msx /home/lembark/.[a-z]* | sort -rn | head -3'
++ sort -rn
++ head -3
++ du -msx /home/lembark/.aceinnovative /home/lembark/.adobe
<snip>
270 /home/lembark/.openoffice
244 /home/lembark/.mozilla
193 /home/lembark/.config
Command execution
We all remember backticks:
a=`ls -al ~`’;
Command execution
We all remember backticks:
a=`ls -al ~`’;
Better off forgotten:
No way to nest them for one.
Hard to read for another.
Command execution
BASH offers a better way:
$( ... )
i.e., “interpolate subshell output”.
Output of arbitrary commands:
files=$(ls ~);
jobs=$( grep ‘MHz’ /proc/cpuinfo | wc -l );
echo -e “DiskHogz:n$(du -msx *|sort -rn|head)”;
Twisting a path with basename
basename
locates
input for
next step.
cmd=’/image/bin/extract-hi-res’;
dir=’../raw’;
cd high-res || exit -1;
for i in ../low-res/culled/*;
do
echo “Input: ‘$i’”;
$cmd $dir/$(basename $i .ppm).nef;
done
Twisting a path with basename
Quotes
hilite
whitespace
in $1.
Don’t
leave
home
without
them...
cmd=’/image/bin/extract-hi-res’;
dir=’../raw’;
cd high-res || exit -1;
for i in ../low-res/culled/*;
do
echo “Input: ‘$i’”;
$cmd $dir/$(basename $i .ppm).nef;
done
Being there
A “here script” is “appended from stdin”.
Double-quotish.
> perl -MCPAN -E shell <<CPAN 2>&1 | tee a;
upgrade
install Module::FromPerlVer
q
CPAN
Being there
A “here script” is “appended from stdin”.
Double-quotish, into stdin.
> perl -MCPAN -E shell <<CPAN 2>&1 | tee a;
upgrade
install Module::FromPerlVer
q
CPAN
Being there
Closing tag sends EOF (^D) to command:
> perl -MCPAN -E shell <<CPAN 2>&1 | tee a;
upgrade
install Module::FromPerlVer
CPAN
Being there
module=’Module::FromPerlVer’;
> perl -MCPAN -E shell <<CPAN 2>&1 | tee a;
upgrade
install $module
CPAN
Being there
#!/bin/bash
...
path=”$mysql_d/$tspace”;
mkdir -p $path || exit -2;
mysql -U$user -P$pass <<SQL || exit -3;
create tablespace $tspace
using ‘$path’ … ;
create table big ( … ) tablespace $tspace;
SQL
Being there
mysql -U$user -P$pass <<SQL || exit -3;
create tablespace $tspace
using ‘$path’ … ;
create table
$(cat $table-1.sql)
tablespace $tspace;
SQL
Slicing with curlies
Remove strings from the head or tail of a string.
${i#glob} ${i%glob}
${i##glob} ${i%%glob}
Slicing with curlies
Slice the head:
${i#glob}
${i##glob}
# is shortest match
## is longest match
Slicing with curlies
Slice the tail:
${i%glob}
${i%%glob}
% is shortest match
%% is longest match
Stripping a prefix.
Say you want to prefix ‘/opt/bin’ onto a PATH.
But it may already be there.
You don’t know if someone else hacked the path.
Q: How can we put ‘/opt/bin’ at the front, once?
Stripping a prefix.
Say you want to prefix ‘/opt/bin’ onto a PATH.
But it may already be there.
You don’t know if someone else hacked the path.
Q: How can we put ‘/opt/bin’ at the front, once?
A: Take it off each time.
Striptease.
‘#’ strips off leading content.
Say we tried this:
PATH=”/opt/bin:${PATH#/opt/bin:}”;
OK, I can run it a hundred times.
Path hack striptease.
‘#’ strips off leading content.
Say we tried this:
PATH=”/opt/bin:${PATH#/opt/bin:}”;
OK, I can run it a hundred times.
Until /opt/bin isn’t first:
“~/bin:/opt/bin: ...”
Globs save the day
Find everything up to the first match:
PATH=”/opt/bin:${PATH#*/opt/bin:}”;
> echo $PATH;
/usr/local/bin:/usr/bin:/bin:/opt/bin:/usr/
i486-pc-linux-gnu/gcc-bin/4.1.2
Globs save the day
Find everything up to the first match:
PATH=”/opt/bin:${PATH#*/opt/bin:}”;
> echo ${PATH#*/opt/bin:};
+ echo /usr/local/bin:/usr/bin:/bin:/opt/bin:/
usr/i486-pc-linux-gnu/gcc-bin/4.1.2
Globs save the day
Find everything up to the first match:
PATH=”/opt/bin:${PATH#*/opt/bin:}”;
> echo ${PATH#*/opt/bin:};
+ echo /usr/local/bin:/usr/bin:/bin:/opt/bin:/
usr/i486-pc-linux-gnu/gcc-bin/4.1.2
Globs save the day
Find everything up to the first match:
PATH=”/opt/bin:${PATH#*/opt/bin:}”;
/usr/i486-pc-linux-gnu/gcc-bin/4.1.2
Fixing the path
Takes a bit more logic:
Strip /opt/bin out of the path.
Paste it onto the front.
Globs aren’t smart enough.
Fixing the path
Takes a bit more logic:
First break up the path.
> echo $PATH | tr ':' "n"
/opt/bin
/usr/local/bin
/usr/bin
/opt/bin
/bin
/usr/i486-pc-linux-gnu/gcc-bin/4.1.2
Fixing the path
Takes a bit more logic:
Then remove ‘/opt/bin’.
> echo $PATH | tr ':' "n" | grep -v '/opt/bin'
/usr/local/bin
/usr/bin
/bin
/usr/i486-pc-linux-gnu/gcc-bin/4.1.2
Fixing the path
Takes a bit more logic:
Recombine them.
> a=$(echo $PATH | tr ':' "n" |
grep -v '/opt/bin' | tr "n" ':');
> echo $a
/usr/local/bin:/usr/bin:/bin:/usr/i486-pc-linux-
gnu/gcc-bin/4.1.2::
Fixing the path
Takes a bit more logic:
Prefix ‘/opt/bin’.
> a=$(echo $PATH | tr ':' "n" |
grep -v '/opt/bin' | tr "n" ':');
> echo “/opt/bin:$a”;
/opt/bin:/usr/local/bin:/usr/bin:/bin:/usr/i486-
pc-linux-gnu/gcc-bin/4.1.2::
Fixing the path
Takes a bit more logic:
Or, as a one-liner:
> PATH=
"/opt/bin:$(echo $PATH | tr ':' "n" |
grep -v '/opt/bin' | tr -s "n" ':')";
> echo $PATH
/opt/bin:/usr/local/bin:/usr/bin:/bin:/usr/i486-
pc-linux-gnu/gcc-bin/4.1.2:
Quick version of basename
Strip off the longest match to ‘/’:
${file_path##*/}
Relative path within a home directory:
${file_path#$HOME}
Relative path in a sandbox directory:
${file_path##*/$(whoami)/}
Getting some tail
Clean up a directory: ${path%/}
Sandbox root: ${file%$(whoami)/*}
Root of home: ${HOME%$(whoami)*}
Less reliable dirname: ${file_path%/*}
Default values
Common use is with arguments.
> rm -rf $1/*;
What if $1 is empty?
> rm -rf /* # might not be what you want
Dealing with falsity
Common issue: Dealing with a NUL value.
Choose a default.
Assign a default.
Fail.
Use a default value
Lacking an argument, pick a value:
path=${1:-/var/tmp/input};
path=${1:-$input};
path=${1:-/var/cache/$(whoami)};
No effect on $1.
Assign a default value
Empty default assigned a value.
‘$’ interpolation may be nested:
“Default: ‘${default:=/var/tmp/$(whoami)}’”;
“:=” does not work with positional parameters ($1...).
Giving up
Maybe not providing a value is an error.
rm -rf ${path:?Path required.}/*
Code exits with “Path required.” prompt.
For example
#!/bin/bash
# if $1 has a value DEFAULT_PATH is ignored.
# empty $1 checks for non-empty default.
path=${1:-${DEFAULT_PATH:?Empty Default}};
# at this point path is not empty.
The next steps
Special Parameters:
$*, $@, $# Command line
$?, $$, $! Execution
Interpolate command line arguments, process control.
Summary
BASH interpolates variables in one pass.
${...} protect, slice variables
eval multi-pass processing.
<<TAG “here script”
-vx debugging
“Parameter Expansion” in bash(1)
Ad

Recommended

Findbin libs
Findbin libs
Workhorse Computing
 
BSDM with BASH: Command Interpolation
BSDM with BASH: Command Interpolation
Workhorse Computing
 
The $path to knowledge: What little it take to unit-test Perl.
The $path to knowledge: What little it take to unit-test Perl.
Workhorse Computing
 
Memory Manglement in Raku
Memory Manglement in Raku
Workhorse Computing
 
Metadata-driven Testing
Metadata-driven Testing
Workhorse Computing
 
Hypers and Gathers and Takes! Oh my!
Hypers and Gathers and Takes! Oh my!
Workhorse Computing
 
Keeping objects healthy with Object::Exercise.
Keeping objects healthy with Object::Exercise.
Workhorse Computing
 
Object Trampoline: Why having not the object you want is what you need.
Object Trampoline: Why having not the object you want is what you need.
Workhorse Computing
 
Smoking docker
Smoking docker
Workhorse Computing
 
Short Introduction To "perl -d"
Short Introduction To "perl -d"
Workhorse Computing
 
Get your teeth into Plack
Get your teeth into Plack
Workhorse Computing
 
Unit Testing Lots of Perl
Unit Testing Lots of Perl
Workhorse Computing
 
Getting Testy With Perl6
Getting Testy With Perl6
Workhorse Computing
 
Getting testy with Perl
Getting testy with Perl
Workhorse Computing
 
Effective Benchmarks
Effective Benchmarks
Workhorse Computing
 
Perl6 Regexen: Reduce the line noise in your code.
Perl6 Regexen: Reduce the line noise in your code.
Workhorse Computing
 
Ethiopian multiplication in Perl6
Ethiopian multiplication in Perl6
Workhorse Computing
 
Building and Distributing PostgreSQL Extensions Without Learning C
Building and Distributing PostgreSQL Extensions Without Learning C
David Wheeler
 
Troubleshooting Puppet
Troubleshooting Puppet
Thomas Howard Uphill
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)
Kang-min Liu
 
Utility Modules That You Should Know About
Utility Modules That You Should Know About
joshua.mcadams
 
Barely Legal Xxx Perl Presentation
Barely Legal Xxx Perl Presentation
Attila Balazs
 
I, For One, Welcome Our New Perl6 Overlords
I, For One, Welcome Our New Perl6 Overlords
heumann
 
Replacing "exec" with a type and provider: Return manifests to a declarative ...
Replacing "exec" with a type and provider: Return manifests to a declarative ...
Puppet
 
Perl web frameworks
Perl web frameworks
diego_k
 
Perl6 in-production
Perl6 in-production
Andrew Shitov
 
Working with databases in Perl
Working with databases in Perl
Laurent Dami
 
Webrtc mojo
Webrtc mojo
bpmedley
 
One-Liners to Rule Them All
One-Liners to Rule Them All
egypt
 
Talk Unix Shell Script
Talk Unix Shell Script
Dr.Ravi
 

More Related Content

What's hot (20)

Smoking docker
Smoking docker
Workhorse Computing
 
Short Introduction To "perl -d"
Short Introduction To "perl -d"
Workhorse Computing
 
Get your teeth into Plack
Get your teeth into Plack
Workhorse Computing
 
Unit Testing Lots of Perl
Unit Testing Lots of Perl
Workhorse Computing
 
Getting Testy With Perl6
Getting Testy With Perl6
Workhorse Computing
 
Getting testy with Perl
Getting testy with Perl
Workhorse Computing
 
Effective Benchmarks
Effective Benchmarks
Workhorse Computing
 
Perl6 Regexen: Reduce the line noise in your code.
Perl6 Regexen: Reduce the line noise in your code.
Workhorse Computing
 
Ethiopian multiplication in Perl6
Ethiopian multiplication in Perl6
Workhorse Computing
 
Building and Distributing PostgreSQL Extensions Without Learning C
Building and Distributing PostgreSQL Extensions Without Learning C
David Wheeler
 
Troubleshooting Puppet
Troubleshooting Puppet
Thomas Howard Uphill
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)
Kang-min Liu
 
Utility Modules That You Should Know About
Utility Modules That You Should Know About
joshua.mcadams
 
Barely Legal Xxx Perl Presentation
Barely Legal Xxx Perl Presentation
Attila Balazs
 
I, For One, Welcome Our New Perl6 Overlords
I, For One, Welcome Our New Perl6 Overlords
heumann
 
Replacing "exec" with a type and provider: Return manifests to a declarative ...
Replacing "exec" with a type and provider: Return manifests to a declarative ...
Puppet
 
Perl web frameworks
Perl web frameworks
diego_k
 
Perl6 in-production
Perl6 in-production
Andrew Shitov
 
Working with databases in Perl
Working with databases in Perl
Laurent Dami
 
Webrtc mojo
Webrtc mojo
bpmedley
 
Perl6 Regexen: Reduce the line noise in your code.
Perl6 Regexen: Reduce the line noise in your code.
Workhorse Computing
 
Ethiopian multiplication in Perl6
Ethiopian multiplication in Perl6
Workhorse Computing
 
Building and Distributing PostgreSQL Extensions Without Learning C
Building and Distributing PostgreSQL Extensions Without Learning C
David Wheeler
 
Good Evils In Perl (Yapc Asia)
Good Evils In Perl (Yapc Asia)
Kang-min Liu
 
Utility Modules That You Should Know About
Utility Modules That You Should Know About
joshua.mcadams
 
Barely Legal Xxx Perl Presentation
Barely Legal Xxx Perl Presentation
Attila Balazs
 
I, For One, Welcome Our New Perl6 Overlords
I, For One, Welcome Our New Perl6 Overlords
heumann
 
Replacing "exec" with a type and provider: Return manifests to a declarative ...
Replacing "exec" with a type and provider: Return manifests to a declarative ...
Puppet
 
Perl web frameworks
Perl web frameworks
diego_k
 
Working with databases in Perl
Working with databases in Perl
Laurent Dami
 
Webrtc mojo
Webrtc mojo
bpmedley
 

Similar to BASH Variables Part 1: Basic Interpolation (20)

One-Liners to Rule Them All
One-Liners to Rule Them All
egypt
 
Talk Unix Shell Script
Talk Unix Shell Script
Dr.Ravi
 
Talk Unix Shell Script 1
Talk Unix Shell Script 1
Dr.Ravi
 
Directories description
Directories description
Dr.M.Karthika parthasarathy
 
04 using and_configuring_bash
04 using and_configuring_bash
Shay Cohen
 
Bash
Bash
KLabCyscorpions-TechBlog
 
Shell scripting
Shell scripting
Mufaddal Haidermota
 
Unleash your inner console cowboy
Unleash your inner console cowboy
Kenneth Geisshirt
 
Licão 09 variables and arrays v2
Licão 09 variables and arrays v2
Acácio Oliveira
 
Learning Bash For linux Command Line
Learning Bash For linux Command Line
Mohamed Alaa El-Din
 
Shell scripting
Shell scripting
Manav Prasad
 
Class 2
Class 2
dduncan3
 
Bash production guide
Bash production guide
Adrien Mahieux
 
Linux
Linux
merlin deepika
 
Linux
Linux
merlin deepika
 
Linux
Linux
Yuvaraja Rajenderan
 
Linux
Linux
HAINIRMALRAJ
 
Linux
Linux
RittikaBaksi
 
Shell intro
Shell intro
Teja Bheemanapally
 
Linux com
Linux com
MohanKumar Palanichamy
 
Ad

More from Workhorse Computing (17)

Object::Trampoline: Follow the bouncing object.
Object::Trampoline: Follow the bouncing object.
Workhorse Computing
 
Wheels we didn't re-invent: Perl's Utility Modules
Wheels we didn't re-invent: Perl's Utility Modules
Workhorse Computing
 
mro-every.pdf
mro-every.pdf
Workhorse Computing
 
Paranormal statistics: Counting What Doesn't Add Up
Paranormal statistics: Counting What Doesn't Add Up
Workhorse Computing
 
Generating & Querying Calendar Tables in Posgresql
Generating & Querying Calendar Tables in Posgresql
Workhorse Computing
 
The W-curve and its application.
The W-curve and its application.
Workhorse Computing
 
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
Workhorse Computing
 
Neatly folding-a-tree
Neatly folding-a-tree
Workhorse Computing
 
Light my-fuse
Light my-fuse
Workhorse Computing
 
Paranormal stats
Paranormal stats
Workhorse Computing
 
Shared Object images in Docker: What you need is what you want.
Shared Object images in Docker: What you need is what you want.
Workhorse Computing
 
Putting some "logic" in LVM.
Putting some "logic" in LVM.
Workhorse Computing
 
Selenium sandwich-3: Being where you aren't.
Selenium sandwich-3: Being where you aren't.
Workhorse Computing
 
Selenium sandwich-2
Selenium sandwich-2
Workhorse Computing
 
Selenium Sandwich Part 1: Data driven Selenium
Selenium Sandwich Part 1: Data driven Selenium
Workhorse Computing
 
Docker perl build
Docker perl build
Workhorse Computing
 
Designing net-aws-glacier
Designing net-aws-glacier
Workhorse Computing
 
Object::Trampoline: Follow the bouncing object.
Object::Trampoline: Follow the bouncing object.
Workhorse Computing
 
Wheels we didn't re-invent: Perl's Utility Modules
Wheels we didn't re-invent: Perl's Utility Modules
Workhorse Computing
 
Paranormal statistics: Counting What Doesn't Add Up
Paranormal statistics: Counting What Doesn't Add Up
Workhorse Computing
 
Generating & Querying Calendar Tables in Posgresql
Generating & Querying Calendar Tables in Posgresql
Workhorse Computing
 
The W-curve and its application.
The W-curve and its application.
Workhorse Computing
 
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
Neatly Hashing a Tree: FP tree-fold in Perl5 & Perl6
Workhorse Computing
 
Shared Object images in Docker: What you need is what you want.
Shared Object images in Docker: What you need is what you want.
Workhorse Computing
 
Selenium sandwich-3: Being where you aren't.
Selenium sandwich-3: Being where you aren't.
Workhorse Computing
 
Selenium Sandwich Part 1: Data driven Selenium
Selenium Sandwich Part 1: Data driven Selenium
Workhorse Computing
 
Ad

Recently uploaded (20)

FIDO Seminar: Authentication for a Billion Consumers - Amazon.pptx
FIDO Seminar: Authentication for a Billion Consumers - Amazon.pptx
FIDO Alliance
 
FIDO Alliance Seminar State of Passkeys.pptx
FIDO Alliance Seminar State of Passkeys.pptx
FIDO Alliance
 
ENERGY CONSUMPTION CALCULATION IN ENERGY-EFFICIENT AIR CONDITIONER.pdf
ENERGY CONSUMPTION CALCULATION IN ENERGY-EFFICIENT AIR CONDITIONER.pdf
Muhammad Rizwan Akram
 
Viral>Wondershare Filmora 14.5.18.12900 Crack Free Download
Viral>Wondershare Filmora 14.5.18.12900 Crack Free Download
Puppy jhon
 
FIDO Seminar: Perspectives on Passkeys & Consumer Adoption.pptx
FIDO Seminar: Perspectives on Passkeys & Consumer Adoption.pptx
FIDO Alliance
 
FIDO Seminar: New Data: Passkey Adoption in the Workforce.pptx
FIDO Seminar: New Data: Passkey Adoption in the Workforce.pptx
FIDO Alliance
 
“Key Requirements to Successfully Implement Generative AI in Edge Devices—Opt...
“Key Requirements to Successfully Implement Generative AI in Edge Devices—Opt...
Edge AI and Vision Alliance
 
“From Enterprise to Makers: Driving Vision AI Innovation at the Extreme Edge,...
“From Enterprise to Makers: Driving Vision AI Innovation at the Extreme Edge,...
Edge AI and Vision Alliance
 
FME for Distribution & Transmission Integrity Management Program (DIMP & TIMP)
FME for Distribution & Transmission Integrity Management Program (DIMP & TIMP)
Safe Software
 
"How to survive Black Friday: preparing e-commerce for a peak season", Yurii ...
"How to survive Black Friday: preparing e-commerce for a peak season", Yurii ...
Fwdays
 
cnc-processing-centers-centateq-p-110-en.pdf
cnc-processing-centers-centateq-p-110-en.pdf
AmirStern2
 
OWASP Barcelona 2025 Threat Model Library
OWASP Barcelona 2025 Threat Model Library
PetraVukmirovic
 
Security Tips for Enterprise Azure Solutions
Security Tips for Enterprise Azure Solutions
Michele Leroux Bustamante
 
OpenPOWER Foundation & Open-Source Core Innovations
OpenPOWER Foundation & Open-Source Core Innovations
IBM
 
Enabling BIM / GIS integrations with Other Systems with FME
Enabling BIM / GIS integrations with Other Systems with FME
Safe Software
 
Tech-ASan: Two-stage check for Address Sanitizer - Yixuan Cao.pdf
Tech-ASan: Two-stage check for Address Sanitizer - Yixuan Cao.pdf
caoyixuan2019
 
Can We Use Rust to Develop Extensions for PostgreSQL? (POSETTE: An Event for ...
Can We Use Rust to Develop Extensions for PostgreSQL? (POSETTE: An Event for ...
NTT DATA Technology & Innovation
 
War_And_Cyber_3_Years_Of_Struggle_And_Lessons_For_Global_Security.pdf
War_And_Cyber_3_Years_Of_Struggle_And_Lessons_For_Global_Security.pdf
biswajitbanerjee38
 
Powering Multi-Page Web Applications Using Flow Apps and FME Data Streaming
Powering Multi-Page Web Applications Using Flow Apps and FME Data Streaming
Safe Software
 
Turning the Page – How AI is Exponentially Increasing Speed, Accuracy, and Ef...
Turning the Page – How AI is Exponentially Increasing Speed, Accuracy, and Ef...
Impelsys Inc.
 
FIDO Seminar: Authentication for a Billion Consumers - Amazon.pptx
FIDO Seminar: Authentication for a Billion Consumers - Amazon.pptx
FIDO Alliance
 
FIDO Alliance Seminar State of Passkeys.pptx
FIDO Alliance Seminar State of Passkeys.pptx
FIDO Alliance
 
ENERGY CONSUMPTION CALCULATION IN ENERGY-EFFICIENT AIR CONDITIONER.pdf
ENERGY CONSUMPTION CALCULATION IN ENERGY-EFFICIENT AIR CONDITIONER.pdf
Muhammad Rizwan Akram
 
Viral>Wondershare Filmora 14.5.18.12900 Crack Free Download
Viral>Wondershare Filmora 14.5.18.12900 Crack Free Download
Puppy jhon
 
FIDO Seminar: Perspectives on Passkeys & Consumer Adoption.pptx
FIDO Seminar: Perspectives on Passkeys & Consumer Adoption.pptx
FIDO Alliance
 
FIDO Seminar: New Data: Passkey Adoption in the Workforce.pptx
FIDO Seminar: New Data: Passkey Adoption in the Workforce.pptx
FIDO Alliance
 
“Key Requirements to Successfully Implement Generative AI in Edge Devices—Opt...
“Key Requirements to Successfully Implement Generative AI in Edge Devices—Opt...
Edge AI and Vision Alliance
 
“From Enterprise to Makers: Driving Vision AI Innovation at the Extreme Edge,...
“From Enterprise to Makers: Driving Vision AI Innovation at the Extreme Edge,...
Edge AI and Vision Alliance
 
FME for Distribution & Transmission Integrity Management Program (DIMP & TIMP)
FME for Distribution & Transmission Integrity Management Program (DIMP & TIMP)
Safe Software
 
"How to survive Black Friday: preparing e-commerce for a peak season", Yurii ...
"How to survive Black Friday: preparing e-commerce for a peak season", Yurii ...
Fwdays
 
cnc-processing-centers-centateq-p-110-en.pdf
cnc-processing-centers-centateq-p-110-en.pdf
AmirStern2
 
OWASP Barcelona 2025 Threat Model Library
OWASP Barcelona 2025 Threat Model Library
PetraVukmirovic
 
Security Tips for Enterprise Azure Solutions
Security Tips for Enterprise Azure Solutions
Michele Leroux Bustamante
 
OpenPOWER Foundation & Open-Source Core Innovations
OpenPOWER Foundation & Open-Source Core Innovations
IBM
 
Enabling BIM / GIS integrations with Other Systems with FME
Enabling BIM / GIS integrations with Other Systems with FME
Safe Software
 
Tech-ASan: Two-stage check for Address Sanitizer - Yixuan Cao.pdf
Tech-ASan: Two-stage check for Address Sanitizer - Yixuan Cao.pdf
caoyixuan2019
 
Can We Use Rust to Develop Extensions for PostgreSQL? (POSETTE: An Event for ...
Can We Use Rust to Develop Extensions for PostgreSQL? (POSETTE: An Event for ...
NTT DATA Technology & Innovation
 
War_And_Cyber_3_Years_Of_Struggle_And_Lessons_For_Global_Security.pdf
War_And_Cyber_3_Years_Of_Struggle_And_Lessons_For_Global_Security.pdf
biswajitbanerjee38
 
Powering Multi-Page Web Applications Using Flow Apps and FME Data Streaming
Powering Multi-Page Web Applications Using Flow Apps and FME Data Streaming
Safe Software
 
Turning the Page – How AI is Exponentially Increasing Speed, Accuracy, and Ef...
Turning the Page – How AI is Exponentially Increasing Speed, Accuracy, and Ef...
Impelsys Inc.
 

BASH Variables Part 1: Basic Interpolation

  • 1. Don’t BASH your head in: Rx for shell variables. Steven Lembark Workhorse Computing [email protected]
  • 2. Quick review BASH is interpreted. Loops are re-parsed. Variables can appear anywhere. Unlike Perl, Python, Ruby, Go, Haskell, Scala, Scheme, Which separate statements from var’s.
  • 3. Basic Variables Assignments to foo: foo=’$files’; literal ‘$files’.
  • 4. Basic Variables Assignments to foo: foo=’$files’; literal ‘$files’. foo=”$files”; interpolated value of files.
  • 5. Basic Variables Assignments to foo: foo=’$files’; literal ‘$files’. foo=”$files”; interpolated value of files. foo=$(ls $files); command output.
  • 6. Basic Variables Assignments to foo: foo=’$files’; literal ‘$files’. foo=”$files”; interpolated value of files. foo=$(ls $files); command output. foo=”$(ls $files)”; string with listing of files.
  • 7. Basic Variables Assignments to foo: foo=’$files’; literal ‘$files’. foo=”$files”; interpolated value of files. foo=$(ls $files); command output. Most of the work is interpolating: echo “Your files are: $(ls $somedir)”;
  • 8. De-mangling variable names > foo=’bar’; > echo “foo$foo”; ”foobar” > echo “$bar_foo”; “” Oops: Variable “bar_foo” doesn’t exist.
  • 9. De-mangling variable names > foo=’bar’; > echo “foo$foo”; ”foobar” > echo “$bar_foo”; “” Isolate ‘foo’ as variable name: “${foo}_bar # “bar_bar”
  • 12. Variable commands # interpolate each command into the loop for i in $cmd1 $cmd2 $cmd3 do $i $args; done
  • 15. Really, anywhere! foo=’bar’; $foo=’blort’; Q: What happens? A: Nada. bash: bar=blort: command not found
  • 16. Your one chance at success BASH parses in two phases: Lexical substitution & tokenizing. Execution. Variables have to expand on the first pass to be used. “foo=blort” cannot be executed, so it failed.
  • 17. A second chance in life ‘eval’ adds one cycle. Interpolates variables. Passes result to the shell. ‘++’ is two levels deep. > eval"$foo=blort"; + eval bar=blort ++ bar=blort > echo $bar; + echo blort blort
  • 18. Or a third chance... eval “eval … “; Work out what is happening: a=’$HOME/?.*’; b=’foo’; c=eval “eval $a $b”’;
  • 19. Verbosity & Execution See what bash is doing with the variables: > set -vx;
  • 20. Verbosity & Execution See what bash is doing with the variables: > set -vx; echo -ne "033]0;./$(basename $PWD) 007" +++ basename /sandbox/lembark/writings/RockfordLUG/bash ++ echo -ne '033]0;./bash 007' >
  • 21. Verbosity & Execution See what bash is doing with the variables: > set -vx; echo -ne "033]0;./$(basename $PWD) 007" +++ basename /sandbox/lembark/writings/RockfordLUG/bash ++ echo -ne '033]0;./bash 007' >
  • 22. “unset” removes variables > unset PROMPT_COMMAND; > set -vx; >
  • 23. Or set verbosity in the script #!/bin/bash -vx … or localize the verbosity: set -vx; do something set -;
  • 24. Verbosity & Execution > unset PROMPT_COMMAND; > set -vx; > foo=bar; what I typed foo=bar; what BASH read + foo=bar single ‘+’is one level deep
  • 25. Verbosity & Execution > unset PROMPT_COMMAND; > set -vx; > foo=bar; what I typed foo=bar; what BASH read + foo=bar single ‘+’is one level deep > $foo='blort'; >foo='blort'; + bar=blort no second chance to re-parse
  • 26. Verbosity & Execution > unset PROMPT_COMMAND; > set -vx; > foo=bar; what I typed foo=bar; what BASH read + foo=bar single ‘+’is one level deep > $foo='blort'; >foo='blort'; + bar=blort no second chance to re-parse bash: bar=blort: command not found
  • 27. Why use ‘-vx’? -v alone is useful sometimes. -x alone usually isn’t.
  • 28. Example: Hidden disk hogs #!/bin/bash dirs="/home/$(whoami)/.*"; cmd="du -msx $dirs | sort -rn | head -3"; eval "$cmd";
  • 29. Buggy hogs $ ./y 1232 /home/lembark/. 0 /home/lembark/..
  • 30. Add verbosity #!/bin/bash set -vx; dirs="/home/$(whoami)/.*"; cmd="du -msx $dirs | sort -rn | head -3"; eval "$cmd";
  • 31. Shows the bug: . & .. $ ./y dirs="/home/$(whoami)/.*"; ++ whoami + dirs='/home/lembark/.*' cmd="du -msx $dirs | sort -rn | head -3"; + cmd='du -msx /home/lembark/.* | sort -rn | head -3' eval "$cmd"; + eval 'du -msx /home/lembark/.* | sort -rn | head -3' du -msx /home/lembark/.* | sort -rn | head -3 ++ sort -rn ++ head -3 ++ du -msx /home/lembark/. /home/lembark/.. /home/lembark/.aceinnovative /home/lembark/.adobe <snip> 1232 /home/lembark/. 0 /home/lembark/..
  • 32. Fix: Add a letter #!/bin/bash set -vx; dirs="/home/$(whoami)/.[a-z]*"; cmd="du -msx $dirs | sort -rn | head -3"; eval "$cmd";
  • 33. Start with the right dirs $ ./y dirs="/home/$(whoami)/.[a-z]*"; ++ whoami + dirs='/home/lembark/.[a-z]*' cmd="du -msx $dirs | sort -rn | head -3"; + cmd='du -msx /home/lembark/.[a-z]* | sort -rn | head -3' eval "$cmd"; + eval 'du -msx /home/lembark/.[a-z]* | sort -rn | head -3' du -msx /home/lembark/.[a-z]* | sort -rn | head -3 ++ sort -rn ++ head -3 ++ du -msx /home/lembark/.aceinnovative /home/lembark/.adobe <snip> 270 /home/lembark/.openoffice 244 /home/lembark/.mozilla 193 /home/lembark/.config
  • 34. Compare: Only “-v” $ ./y dirs="/home/$(whoami)/.[a-z]*"; cmd="du -msx $dirs | sort -rn | head -3"; eval "$cmd"; du -msx /home/lembark/.[a-z]* | sort -rn | head -3 270 /home/lembark/.openoffice 244 /home/lembark/.mozilla 193 /home/lembark/.config
  • 35. Compare: Only “-x” $ ./y ++ whoami + dirs='/home/lembark/.[a-z]*' + cmd='du -msx /home/lembark/.[a-z]* | sort -rn | head -3' + eval 'du -msx /home/lembark/.[a-z]* | sort -rn | head -3' ++ sort -rn ++ head -3 ++ du -msx /home/lembark/.aceinnovative /home/lembark/.adobe <snip> 270 /home/lembark/.openoffice 244 /home/lembark/.mozilla 193 /home/lembark/.config
  • 36. Command execution We all remember backticks: a=`ls -al ~`’;
  • 37. Command execution We all remember backticks: a=`ls -al ~`’; Better off forgotten: No way to nest them for one. Hard to read for another.
  • 38. Command execution BASH offers a better way: $( ... ) i.e., “interpolate subshell output”. Output of arbitrary commands: files=$(ls ~); jobs=$( grep ‘MHz’ /proc/cpuinfo | wc -l ); echo -e “DiskHogz:n$(du -msx *|sort -rn|head)”;
  • 39. Twisting a path with basename basename locates input for next step. cmd=’/image/bin/extract-hi-res’; dir=’../raw’; cd high-res || exit -1; for i in ../low-res/culled/*; do echo “Input: ‘$i’”; $cmd $dir/$(basename $i .ppm).nef; done
  • 40. Twisting a path with basename Quotes hilite whitespace in $1. Don’t leave home without them... cmd=’/image/bin/extract-hi-res’; dir=’../raw’; cd high-res || exit -1; for i in ../low-res/culled/*; do echo “Input: ‘$i’”; $cmd $dir/$(basename $i .ppm).nef; done
  • 41. Being there A “here script” is “appended from stdin”. Double-quotish. > perl -MCPAN -E shell <<CPAN 2>&1 | tee a; upgrade install Module::FromPerlVer q CPAN
  • 42. Being there A “here script” is “appended from stdin”. Double-quotish, into stdin. > perl -MCPAN -E shell <<CPAN 2>&1 | tee a; upgrade install Module::FromPerlVer q CPAN
  • 43. Being there Closing tag sends EOF (^D) to command: > perl -MCPAN -E shell <<CPAN 2>&1 | tee a; upgrade install Module::FromPerlVer CPAN
  • 44. Being there module=’Module::FromPerlVer’; > perl -MCPAN -E shell <<CPAN 2>&1 | tee a; upgrade install $module CPAN
  • 45. Being there #!/bin/bash ... path=”$mysql_d/$tspace”; mkdir -p $path || exit -2; mysql -U$user -P$pass <<SQL || exit -3; create tablespace $tspace using ‘$path’ … ; create table big ( … ) tablespace $tspace; SQL
  • 46. Being there mysql -U$user -P$pass <<SQL || exit -3; create tablespace $tspace using ‘$path’ … ; create table $(cat $table-1.sql) tablespace $tspace; SQL
  • 47. Slicing with curlies Remove strings from the head or tail of a string. ${i#glob} ${i%glob} ${i##glob} ${i%%glob}
  • 48. Slicing with curlies Slice the head: ${i#glob} ${i##glob} # is shortest match ## is longest match
  • 49. Slicing with curlies Slice the tail: ${i%glob} ${i%%glob} % is shortest match %% is longest match
  • 50. Stripping a prefix. Say you want to prefix ‘/opt/bin’ onto a PATH. But it may already be there. You don’t know if someone else hacked the path. Q: How can we put ‘/opt/bin’ at the front, once?
  • 51. Stripping a prefix. Say you want to prefix ‘/opt/bin’ onto a PATH. But it may already be there. You don’t know if someone else hacked the path. Q: How can we put ‘/opt/bin’ at the front, once? A: Take it off each time.
  • 52. Striptease. ‘#’ strips off leading content. Say we tried this: PATH=”/opt/bin:${PATH#/opt/bin:}”; OK, I can run it a hundred times.
  • 53. Path hack striptease. ‘#’ strips off leading content. Say we tried this: PATH=”/opt/bin:${PATH#/opt/bin:}”; OK, I can run it a hundred times. Until /opt/bin isn’t first: “~/bin:/opt/bin: ...”
  • 54. Globs save the day Find everything up to the first match: PATH=”/opt/bin:${PATH#*/opt/bin:}”; > echo $PATH; /usr/local/bin:/usr/bin:/bin:/opt/bin:/usr/ i486-pc-linux-gnu/gcc-bin/4.1.2
  • 55. Globs save the day Find everything up to the first match: PATH=”/opt/bin:${PATH#*/opt/bin:}”; > echo ${PATH#*/opt/bin:}; + echo /usr/local/bin:/usr/bin:/bin:/opt/bin:/ usr/i486-pc-linux-gnu/gcc-bin/4.1.2
  • 56. Globs save the day Find everything up to the first match: PATH=”/opt/bin:${PATH#*/opt/bin:}”; > echo ${PATH#*/opt/bin:}; + echo /usr/local/bin:/usr/bin:/bin:/opt/bin:/ usr/i486-pc-linux-gnu/gcc-bin/4.1.2
  • 57. Globs save the day Find everything up to the first match: PATH=”/opt/bin:${PATH#*/opt/bin:}”; /usr/i486-pc-linux-gnu/gcc-bin/4.1.2
  • 58. Fixing the path Takes a bit more logic: Strip /opt/bin out of the path. Paste it onto the front. Globs aren’t smart enough.
  • 59. Fixing the path Takes a bit more logic: First break up the path. > echo $PATH | tr ':' "n" /opt/bin /usr/local/bin /usr/bin /opt/bin /bin /usr/i486-pc-linux-gnu/gcc-bin/4.1.2
  • 60. Fixing the path Takes a bit more logic: Then remove ‘/opt/bin’. > echo $PATH | tr ':' "n" | grep -v '/opt/bin' /usr/local/bin /usr/bin /bin /usr/i486-pc-linux-gnu/gcc-bin/4.1.2
  • 61. Fixing the path Takes a bit more logic: Recombine them. > a=$(echo $PATH | tr ':' "n" | grep -v '/opt/bin' | tr "n" ':'); > echo $a /usr/local/bin:/usr/bin:/bin:/usr/i486-pc-linux- gnu/gcc-bin/4.1.2::
  • 62. Fixing the path Takes a bit more logic: Prefix ‘/opt/bin’. > a=$(echo $PATH | tr ':' "n" | grep -v '/opt/bin' | tr "n" ':'); > echo “/opt/bin:$a”; /opt/bin:/usr/local/bin:/usr/bin:/bin:/usr/i486- pc-linux-gnu/gcc-bin/4.1.2::
  • 63. Fixing the path Takes a bit more logic: Or, as a one-liner: > PATH= "/opt/bin:$(echo $PATH | tr ':' "n" | grep -v '/opt/bin' | tr -s "n" ':')"; > echo $PATH /opt/bin:/usr/local/bin:/usr/bin:/bin:/usr/i486- pc-linux-gnu/gcc-bin/4.1.2:
  • 64. Quick version of basename Strip off the longest match to ‘/’: ${file_path##*/} Relative path within a home directory: ${file_path#$HOME} Relative path in a sandbox directory: ${file_path##*/$(whoami)/}
  • 65. Getting some tail Clean up a directory: ${path%/} Sandbox root: ${file%$(whoami)/*} Root of home: ${HOME%$(whoami)*} Less reliable dirname: ${file_path%/*}
  • 66. Default values Common use is with arguments. > rm -rf $1/*; What if $1 is empty? > rm -rf /* # might not be what you want
  • 67. Dealing with falsity Common issue: Dealing with a NUL value. Choose a default. Assign a default. Fail.
  • 68. Use a default value Lacking an argument, pick a value: path=${1:-/var/tmp/input}; path=${1:-$input}; path=${1:-/var/cache/$(whoami)}; No effect on $1.
  • 69. Assign a default value Empty default assigned a value. ‘$’ interpolation may be nested: “Default: ‘${default:=/var/tmp/$(whoami)}’”; “:=” does not work with positional parameters ($1...).
  • 70. Giving up Maybe not providing a value is an error. rm -rf ${path:?Path required.}/* Code exits with “Path required.” prompt.
  • 71. For example #!/bin/bash # if $1 has a value DEFAULT_PATH is ignored. # empty $1 checks for non-empty default. path=${1:-${DEFAULT_PATH:?Empty Default}}; # at this point path is not empty.
  • 72. The next steps Special Parameters: $*, $@, $# Command line $?, $$, $! Execution Interpolate command line arguments, process control.
  • 73. Summary BASH interpolates variables in one pass. ${...} protect, slice variables eval multi-pass processing. <<TAG “here script” -vx debugging “Parameter Expansion” in bash(1)