Date post: | 16-Apr-2017 |
Category: |
Engineering |
Upload: | kel-cecil |
View: | 319 times |
Download: | 2 times |
Coming Out of Your Shell
Kel Cecil@praisechaos
bashCreated by Brian Fox in1989Stallman was not pleasedwith
for an open shellanother developer's
progress
zshCreated by Paul Falstad in1990 while a student atPrinceton.Named after for Yaleprofessor Zhong Shaowhose login id was "zsh"
Shared history (like FTP and TCP support)
Extended file globbingTheme-able prompts
Sweet loadable modules
zsh configured with oh-my-zsh and demonstrating extended globbing
(Some) zsh Features
fishOrignally written by AxelLiljencrantz and released in2005"friendly interactive shell"Considered an "exotic"shell
Does not derive syntaxfrom Bourne or c shells
fish's design is opinionated
(Some) fish Features
Selectable, searchable tab-completion menu with helpfuldescriptions
Web configuration tool (fish_config)
Aesthetic feedback on completions and moreShell completions by parsing man pages
Event handlers
Digging a Little Deeper
GlobbingReferencing Files with Ease
What is Globbing?The ability to get a list of filenamesmatching some descriptive string
Proficiency with globbing can save a lot oftime.
Recursive WildcardsWorks out of the box in zsh, fish
Recursive Wildcardsbash 4.x
Opt-in Features for bash
There are several opt-in features for bash.Opt-in is intended to preserve default behaviorwhere desired.A list of opt-in features is available on the
.Be sure to check it out if you're a bash person.
shoptbuiltin info page
zsh's Glob QualifiersWhat if I'd like to find an .iso in my Downloads folder?
Filter down to images that are larger than 1 GBModified less than 1 Month Ago
*.iso(.Lg+1mM-1)
zsh's estringsestrings allow you to use a comparison as a conditionfor expansion
~/code/*(/e:'[[ -e ${REPLY}/.git ]]':)
zsh's glob qualifier abuse
Glob qualifiers can be nasty if abused.
~/code/*(-FUGmM+3e:'[[ -e ${REPLY}/.git ]]':^mM+12)
zsh's glob qualifier abuse
~/code/*(-FUGe:'[[ -e ${REPLY}/.git ]]':^mM+12)
Non-empty directories (F) in the code directory in myhome directory that are not symlinks (-)Directories are owned by the current user (U) AND thecurrent user's primary group (G).Include the directory if it includes a .git directory(estring).Do not include ( ^ ) directories modified more than 12 months ago.
There's plenty more...Be sure to check out zsh's Expansion manual page
ScriptingMaking the shell work for you
A simple example scriptTakes a list of files and two wordsLoops through each of the files
Ensure the file is a regular fileReplace the first word with the second wordOutput a status line
Example:./chtext.sh bruceBanner incredibleHulk ./data/*.txt
#!/bin/bash# chtext - change text within multiple files
if [ $# -lt 3 ]; then echo >&2 "usage: chtext old new [file ...]" exit 1fi
OLD="$1"NEW="$2"shift 2
for FILEdo echo >&2 "chtext: change ${FILE}: ${OLD} to ${NEW}" if [ -r "${FILE}" ] then if sed "s|${OLD}|${NEW}|g" < "${FILE}" > /tmp/ct$$ then mv /tmp/ct$$ "${FILE}" else echo >&2 "chtext: could not change file: ${FILE}" fi fidone
bash
#!/bin/bash# chtext - change text within multiple files
if [ $# -lt 3 ]; then echo >&2 "usage: chtext old new [file ...]" exit 1fi
OLD="$1"NEW="$2"shift 2
for FILEdo echo >&2 "chtext: change ${FILE}: ${OLD} to ${NEW}" if [ -r "${FILE}" ] then if sed "s|${OLD}|${NEW}|g" < "${FILE}" > /tmp/ct$$ then mv /tmp/ct$$ "${FILE}" else echo >&2 "chtext: could not change file: ${FILE}" fi fidone
bash
Check if we've suppliedfewer than threeparameters.Exit with an error codeof 1 if so.
#!/bin/bash# chtext - change text within multiple files
if [ $# -lt 3 ]; then echo >&2 "usage: chtext old new [file ...]" exit 1fi
OLD="$1"NEW="$2"shift 2
for FILEdo echo >&2 "chtext: change ${FILE}: ${OLD} to ${NEW}" if [ -r "${FILE}" ] then if sed "s|${OLD}|${NEW}|g" < "${FILE}" > /tmp/ct$$ then mv /tmp/ct$$ "${FILE}" else echo >&2 "chtext: could not change file: ${FILE}" fi fidone
bashSet our word to bereplaced as OLD andthe replacement wordas NEWShift the scriptarguments two places.
Move all arraycontents left twoplaces.This removes thefirst two array items.
#!/bin/bash# chtext - change text within multiple files
if [ $# -lt 3 ]; then echo >&2 "usage: chtext old new [file ...]" exit 1fi
OLD="$1"NEW="$2"shift 2
for FILEdo echo >&2 "chtext: change ${FILE}: ${OLD} to ${NEW}" if [ -r "${FILE}" ] then if sed "s|${OLD}|${NEW}|g" < "${FILE}" > /tmp/ct$$ then mv /tmp/ct$$ "${FILE}" else echo >&2 "chtext: could not change file: ${FILE}" fi fidone
bash
Loop through theremaining scriptarguments.Set each argument tothe FILE variable.This isn't exactlyintuitive...
#!/bin/bash# chtext - change text within multiple files
if [ $# -lt 3 ]; then echo >&2 "usage: chtext old new [file ...]" exit 1fi
OLD="$1"NEW="$2"shift 2
for FILEdo echo >&2 "chtext: change ${FILE}: ${OLD} to ${NEW}" if [ -r "${FILE}" ] then if sed "s|${OLD}|${NEW}|g" < "${FILE}" > /tmp/ct$$ then mv /tmp/ct$$ "${FILE}" else echo >&2 "chtext: could not change file: ${FILE}" fi fidone
bashCheck if the file is aregular file. Perform a sed toreplace the OLD wordwith the new word andwrite to a temp file.
$$ represents theprocess ID for thescript.
If the sed returns a zerostatus code, thenreplace the file.
fish is a little different...bash strives to be POSIX compliantzsh strives to be compatible with bashfish does it's own thing
fish is not POSIX compliant and considers that tobe a feature.The scripting language is intended to be moresimple.
#!/usr/bin/env fish# chtext - change text within multiple files
set VALUES (count $argv)
if math (count $argv) "<3" > /dev/null echo >&2 "usage: chtext old new [file ...]" exit 1end
set OLD $argv[1]set NEW $argv[2]
for FILE in $argv[3..-1] echo >&2 "chtext: change $FILE: $OLD to $NEW" if test -f $FILE if sed "s|$OLD|$NEW|g" < "$FILE" > /tmp/ct%self mv /tmp/ct%self "$FILE" else echo >&2 "chtext: could not change file: $FILE" end endend
fish
#!/usr/bin/env fish# chtext - change text within multiple files
if math (count $argv) "<3" > /dev/null echo >&2 "usage: chtext old new [file ...]" exit 1end
set OLD $argv[1]set NEW $argv[2]
for FILE in $argv[3..-1] echo >&2 "chtext: change $FILE: $OLD to $NEW" if test -f $FILE if sed "s|$OLD|$NEW|g" < "$FILE" > /tmp/ct%self mv /tmp/ct%self "$FILE" else echo >&2 "chtext: could not change file: $FILE" end endend
fishCheck to see if ourarguments are lessthan 3.Script arguments arestored in $argvWe use the mathbuiltin for ourcomparisonRedirect the mathoutput to /dev/null toavoid printing ouranswer on stdout
#!/usr/bin/env fish# chtext - change text within multiple files
if math (count $argv) "<3" > /dev/null echo >&2 "usage: chtext old new [file ...]" exit 1end
set OLD $argv[1]set NEW $argv[2]
for FILE in $argv[3..-1] echo >&2 "chtext: change $FILE: $OLD to $NEW" if test -f $FILE if sed "s|$OLD|$NEW|g" < "$FILE" > /tmp/ct%self mv /tmp/ct%self "$FILE" else echo >&2 "chtext: could not change file: $FILE" end endend
fishfish uses "set" forvariable assignment.
#!/usr/bin/env fish# chtext - change text within multiple files
if math (count $argv) "<3" > /dev/null echo >&2 "usage: chtext old new [file ...]" exit 1end
set OLD $argv[1]set NEW $argv[2]
for FILE in $argv[3..-1] echo >&2 "chtext: change $FILE: $OLD to $NEW" if test -f $FILE if sed "s|$OLD|$NEW|g" < "$FILE" > /tmp/ct%self mv /tmp/ct%self "$FILE" else echo >&2 "chtext: could not change file: $FILE" end endend
fishList ranges can bespecified using ".."The last item in thelist can be identifiedby using "-1"
#!/usr/bin/env fish# chtext - change text within multiple files
if math (count $argv) "<3" > /dev/null echo >&2 "usage: chtext old new [file ...]" exit 1end
set OLD $argv[1]set NEW $argv[2]
for FILE in $argv[3..-1] echo >&2 "chtext: change $FILE: $OLD to $NEW" if test -f $FILE if sed "s|$OLD|$NEW|g" < "$FILE" > /tmp/ct%self mv /tmp/ct%self "$FILE" else echo >&2 "chtext: could not change file: $FILE" end endend
fishNotice that variablesdo not have curlybraces "{}"
Curly braces areoptional in bash.fish requires younot use them.fish will be niceabout it.
#!/usr/bin/env fish# chtext - change text within multiple files
if math (count $argv) "<3" > /dev/null echo >&2 "usage: chtext old new [file ...]" exit 1end
set OLD $argv[1]set NEW $argv[2]
for FILE in $argv[3..-1] echo >&2 "chtext: change $FILE: $OLD to $NEW" if test -f $FILE if sed "s|$OLD|$NEW|g" < "$FILE" > /tmp/ct%self mv /tmp/ct%self "$FILE" else echo >&2 "chtext: could not change file: $FILE" end endend
fishfish defers toprograms whenpossible instead ofreimplementingfeatures.This call to testchecks to see if a fileis a regular file.
#!/usr/bin/env fish# chtext - change text within multiple files
if math (count $argv) "<3" > /dev/null echo >&2 "usage: chtext old new [file ...]" exit 1end
set OLD $argv[1]set NEW $argv[2]
for FILE in $argv[3..-1] echo >&2 "chtext: change $FILE: $OLD to $NEW" if test -f $FILE if sed "s|$OLD|$NEW|g" < "$FILE" > /tmp/ct%self mv /tmp/ct%self "$FILE" else echo >&2 "chtext: could not change file: $FILE" end endend
fish%self substitutes theprocess ID in fish.
Using $$ as youwould in bashresults in a helpfulerror message.
if math (count $argv) "<3" > /dev/null echo >&2 "usage: chtext old new [file ...]" exit 1end
set OLD $argv[1]set NEW $argv[2]
for FILE in $argv[3..-1] if test -f $FILE if sed "s|$OLD|$NEW|g" < "$FILE" > /tmp/ct%self mv /tmp/ct%self "$FILE" end endend
if [ $# -lt 3 ]; then echo >&2 "usage: chtext old new [file ...]" exit 1fi
OLD="$1"NEW="$2"shift 2
for FILEdo if [ -r "${FILE}" ] then if sed "s|${OLD}|${NEW}|g" < "${FILE}" > /tmp/ct$$ then mv /tmp/ct$$ "${FILE}" fi fidone
Which do you prefer?
Bash?
or fish?
Frameworks
Why use shell frameworks?Carefully manicured shell scripts can be a lot of work.Community maintained scripts can be higher quality.
oh my zsh! oh my fish! bash it
Take Your Pick!
What are my takeaways?
bash is capable of more than it's givencredit for.zsh is great for people who like to tweakand invest the time into unlocking it's fullpotential.fish is fantastic for useful features right outof the box.All three shells have frameworks to try.We've hardly scratched the surface...
Thanks for Listening!
Twitter: @praisechaos
Web: http://kelcecil.com
Here's a Game Boy Advance running Unix 5!