DEV Community

Bash from scratch: learn enough bash to write your own scripts

Ahmed Musallam on September 10, 2018

You should probably read @maxwell_dev's post: The Shell Introduction I Wish I Had before this I find myself always needing to write shell script...
Collapse
 
erebos-manannan profile image
Erebos Manannán


#!/usr/bin/env sh

You might want to consider replacing sh with bash if you want to actually do BASH scripting. They are different interpreters, and one can lead to vastly different set of available features depending on platform you run it on, while the other will (correctly) crash if the missing features (namely BASH) is missing on the system.

Collapse
 
ahmedmusallam profile image
Ahmed Musallam

I started this post to talk about shell scripting in general. but I think I think you’re right, its confusing that way. I’ll change the shebang to be bash exclusive. Thank you for the feedback!

Collapse
 
erebos-manannan profile image
Erebos Manannán

Both are definitely valid options, just if you want to write for bash then it's better to avoid ambiguity about it. When writing with support for BSD, Busybox, etc. environments in mind (e.g. inside Alpine Linux), sh is the better option, just comes with some extra baggage.

Collapse
 
erebos-manannan profile image
Erebos Manannán • Edited

Instead of referring to some online articles on test conditions, you can just check out man test.

Conditions and most other such things are good to shorthand a bit, and if you're planning on using BASH use [[ ... ]] instead of [ ... ] as they also function differently. Stick to one style for predictability. serverfault.com/a/52050

Slightly compacted formats

if [[ "$FOO" == "1" ]]; then
  ...
else
  ...
fi

for i in 1 2 3 4; do
  echo $i
done

while [[ true ]]; do
  ...
done

Also shellcheck.net/ is an excellent resource to use to check your scripts for common bugs etc. There's even a decent unit testing framework for BASH scripts nowadays: github.com/sstephenson/bats

Collapse
 
ahmedmusallam profile image
Ahmed Musallam

This is fantastic! I’m still new to bash scripting :) but will include this in the article. Great feedback!!

Collapse
 
ahmedmusallam profile image
Ahmed Musallam

I have updated the post, thank you again for the feedback!

Collapse
 
designbradford profile image
Brad Robertson

Excellent article, and very helpful comment discussions as well! The concise descriptions with supporting examples makes it a quick and effective read.

Anyway, wish I had read an article like this 9 months ago-- the information about shift, loops and functions would have gone a long way in the scripts I've been writing to provision our Ubuntu Vagrant VMs for use as localhost web dev environments.

Looking forward to applying some of this. Thx for posting!

Collapse
 
erebos-manannan profile image
Erebos Manannán

Just as a quick comment - you should check out actual provisioning tools, such as SaltStack and Ansible if you want reproducible environments (or event driven infrastructure actions, secret management, easily distributable remote command execution, etc. etc.)

Collapse
 
ahmedmusallam profile image
Ahmed Musallam

Glad you liked it! Honestly, I wrote it after struggling with bash for a few weeks. I was copying and pasting things I did not understand exactly how they worked.. mainly that while-shift loop.

Collapse
 
erebos-manannan profile image
Erebos Manannán

Oh, another thing I just noticed. Generally people like to think "eval is evil", and while imo eval has it's place, especially in BASH, you can avoid using eval with various tricks.

JAVA=$(which java)
APP=$1
EXTRA=""
if [[ "$NEED_EXTRA" == "1" ]]; then
  EXTRA="--extra arg"
fi

"$JAVA" "$APP" $EXTRA

It's got a lot to do with how variable expansion and quoting works.

So in your specific example

COMMAND="mvn clean install -P$PROFILE -Dcrx.user=$USER -Dcrx.password=$PASSWORD"

eval $COMMAND

I would instead write that as

PROFILE="${PROFILE:-autoInstallPackage}"
USER="${USER:-user1}"
PASSWORD="${PASSWORD:-pass1}"
mvn clean install "-P$PROFILE" "-Dcrx.user=$USER" "-Dcrx.password=$PASSWORD"
Collapse
 
ahmedmusallam profile image
Ahmed Musallam

I agree with you that eval, in most languages is viewed as evil. But that's largely because it might be used in applications with a lot of end users, where it is possible for something malicious to happen.

In this case, and for bash, the scripts are for productivity where you (the developer) or your immediate team are the one's running them and they are not meant for production applications.

Overall, I think it is worth pointing that out in the post :)

Collapse
 
maxwell_dev profile image
Max Antonucci

Aww thank you so much for the shout-out in the start! This looks like a great post as well, I've got it on my list to look through in more detail and take notes on the most useful scripts and commands :)

Collapse
 
ahmedmusallam profile image
Ahmed Musallam

you got it! yours was an excellent read :)

Collapse
 
shmdhussain12 profile image
Mohamed Hussain

Thanks Ahmed for this concsice article covers shell scripting essentials which will help in writingand understanding the bash file...my doubt is 1. Do we need to use only the uppercase for the variable?....2. what is the difference between the sh and bash ..what is default in Mac terminal....

Collapse
 
ahmedmusallam profile image
Ahmed Musallam • Edited

Hey, Glad you liked it!

  1. Using uppercase variable names is a naming convention you'll see in most scripts out there. You can chose a different convention :) nothing is stopping you :)
  2. sh stands for shell. bash is a shell. Read @maxwell_dev's post at the beginning of the article.
Collapse
 
moopet profile image
Ben Sinclair

Using uppercase is a convention for variables from the parent environment. Lowercase for variables that are local to our script.
I see people use uppercase all the time, but it's usually just because a lot of scripts don't need local variables and that's how they learnt.
I mean, it doesn't really matter... but I am the cheerleader for Team Lowercase.

Collapse
 
tdubs profile image
Tommy Wu

I just remembered this: thoughtworks.com/insights/blog/pra...

Collapse
 
tdubs profile image
Tommy Wu

a ./go script to run on a project and just have everything work, Dependencies and other projects initiated...

Collapse
 
vicky22rocking profile image
vicky22rocking

Lots of thanks for such a wonderful article

Collapse
 
33nano profile image
Manyong'oments

Awesome article, although i do prefer this type of shebang (#!/bin/sh) as opposed to this type of shebang (#!/usr/bin/env)