Skip to content
Snippets Groups Projects
Commit 0e1de454 authored by Michael Marsh's avatar Michael Marsh
Browse files

bash quick-ref

parent 8220f5e8
No related branches found
No related tags found
No related merge requests found
bash.pdf 0 → 100644
File added
...@@ -53,6 +53,27 @@ Now try: ...@@ -53,6 +53,27 @@ Now try:
The braces give us considerable more control, and some extra features, The braces give us considerable more control, and some extra features,
as we'll see. as we'll see.
It is also possible to set variables for a single command. There
are two ways to do this:
/usr/bin/env a=foo my_command
a=foo my_command
Both of these set the variable `a` to the value `foo`, but *only*
for the environment seen by `my_command`. This is used frequently
to override default variables without changing them:
JAVA_HOME=${HOME}/my_java some_java_program
LD_LIBRARY_PATH=${HOME}/build/lib my_c_program
By convention, script-local variables are lowercase, and more global
variables (like HOME) are uppercase.
Subprocesses typically don't get passed the variables you define. To
change this, you need to export the variable:
export PATH
Parameter Expansion Parameter Expansion
------------------- -------------------
...@@ -71,6 +92,16 @@ details and other expansion options. ...@@ -71,6 +92,16 @@ details and other expansion options.
| | If *s* not provided, remove the pattern | | | If *s* not provided, remove the pattern |
| | # and % perform prefix and suffix matches | | | # and % perform prefix and suffix matches |
We can use this in a script along with variable overriding for handling
script inputs symbolically, rather than positionally:
${target:=foo.txt}
grep foobar ${target}
We would call this (assuming it's called "myscript"):
target=/etc/hosts myscript
Quoting Quoting
------- -------
...@@ -99,16 +130,50 @@ Command Execution ...@@ -99,16 +130,50 @@ Command Execution
There are multiple ways to do this. Consider an executable `foo`: There are multiple ways to do this. Consider an executable `foo`:
| *Invocation* | *Effect* | | *Invocation* | *Effect* |
| ------------ | -------- | | ------------ | -------- |
| `foo` | foo is run as a subprocess normally | | `foo` | foo is run as a subprocess normally |
| `foo &` | foo is run in the background, as execution continues | | `foo &` | foo is run in the background, as execution continues |
| `` `foo` `` | foo is run as a subprocess, and its STDOUT is returned | | `. foo` | foo is run *in the current shell* |
| `$(foo)` | Same as the above | | `(foo)` | a subshell is started, and foo is run as a subproc of it |
| `` `foo` `` | foo is run as a subprocess, and its STDOUT is returned |
| `$(foo)` | Same as the above |
The last two are equivalent, but the $() form is preferable, because The last two are equivalent, but the $() form is preferable, because
it is clearer and can be nested. it is clearer and can be nested.
The dot-execution is useful for snippets of bash code which set
environment variables or define functions. Think of it like an
"include" statement.
The advantage of running in a subshell is that it doesn't impact
the current shell. Here's an example:
for d in * # "*" expands to the contents of the current directory
do
if [ -d $d ] # Test that $d is a directory
then
(cd $d; git pull origin master)
fi
done
If we ran in the parent shell, we would have to make this longer:
cwd=$(pwd)
for d in * # "*" expands to the contents of the current directory
do
if [ -d $d ] # Test that $d is a directory
then
cd $d
git pull origin master
cd $cwd
fi
done
We could use `..` instead of `$cwd`, but then we'd have to worry
about `cd $d` failing. With a subshell, we don't need to worry about
this at all.
Working with Positional Parameters Working with Positional Parameters
---------------------------------- ----------------------------------
...@@ -346,3 +411,104 @@ Let's combine this for command-line argument parsing: ...@@ -346,3 +411,104 @@ Let's combine this for command-line argument parsing:
Functions Functions
--------- ---------
Defining a function:
function my_func {
local a=$1
echo $a
}
Functions begin with the `function` keyword, then a name, and then
the body of the function, in curled braces. The `local` keywords
defines a variable in the function's scope. If not used, the variable
will be defined in the global scope, and hence visible outside of
the function. Positional parameters are redefined for the function's
scope.
Once defined, the function behaves like any other command:
my_func "hello"
You can define particularly useful functions in your ~/.bashrc,
which will be executed (using .) whenever you start a new shell.
Aliases
-------
Common one-liners are often nice to put into simple aliases, which
are defined like:
alias ls='ls -FC'
Here are some aliases I find useful:
alias ls='ls -FC'
alias la='ls -A'
alias ll='ls -l'
alias ltr='ls -ltr'
alias lsd='ls -lsd'
These are defined in my ~/.bashrc. There's also a file called either
~/.bash_profile or ~/.profile, which is only run for a login shell
(that is, only once when you first log in). When you modify one of
these files, make sure you re-dot them
. ~/.bashrc
. ~/.bash_profile
. ~/.profile
Scripting
---------
Some principles I live by:
1. If I'm going to do something more than once, I script it.
2. If I do something once, there's a good chance I'm going to have
to do it again.
Most shells, bash included, treat executable text files specially.
Given no other information, they run them as scripts for the current
shell. *Do not assume that file extensions mean anything.* At the
very least, bash does not care about the name of your file, it only
cares about the content. Naming a file `foo.py` does not mean bash
will treat it as a python file, for instance.
To run the script correctly, there's an easy way and a hard way.
The hard way is to call the appropriate interpreter explicitly:
bash my_shell_script.sh
python my_python_script.py
The easy way is to use a convention called *shebang* (short for
"hash-bang"). The shell will look at the first line of an executable
ASCII file. If that line begins with a shebang, the arguments to
that provide the program with which to run the script:
#! /bin/bash
You can even provide options:
#! /bin/bash -x
For python, there's a better way to call it:
#! /usr/bin/env python
What does this do? We're not actually invoking python directly.
Instead, we invoke env, which passes the parent environment. In
particular, this means it's also using the parent shell's $PATH
variable to determine how to find python. This has a couple of
advantages:
* The location of python may vary from installation to installation,
but env's location is always predictable.
* If you use python virtual environments, this will pick up your
virtualenv python.
As a final note, make sure your scripts are executable! See "chmod"
in the filesystems quick-ref for details, but 99 times out of 100,
you will want to run `chmod a+x` on your script. git keeps track
of file permissions in addition to the contents.
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment