diff --git a/bash.pdf b/bash.pdf new file mode 100644 index 0000000000000000000000000000000000000000..322ffe69b9329623d848e14fdfd8695525b26d29 Binary files /dev/null and b/bash.pdf differ diff --git a/bash.txt b/bash.txt index d9a3335f682992a09b0a414ce41776f6d051b418..9ee29e104fe3efc0e6878b891d5ce8919f33f1d3 100644 --- a/bash.txt +++ b/bash.txt @@ -53,6 +53,27 @@ Now try: The braces give us considerable more control, and some extra features, 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 ------------------- @@ -71,6 +92,16 @@ details and other expansion options. | | If *s* not provided, remove the pattern | | | # 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 ------- @@ -99,16 +130,50 @@ Command Execution There are multiple ways to do this. Consider an executable `foo`: -| *Invocation* | *Effect* | -| ------------ | -------- | -| `foo` | foo is run as a subprocess normally | -| `foo &` | foo is run in the background, as execution continues | -| `` `foo` `` | foo is run as a subprocess, and its STDOUT is returned | -| `$(foo)` | Same as the above | +| *Invocation* | *Effect* | +| ------------ | -------- | +| `foo` | foo is run as a subprocess normally | +| `foo &` | foo is run in the background, as execution continues | +| `. foo` | foo is run *in the current shell* | +| `(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 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 ---------------------------------- @@ -346,3 +411,104 @@ Let's combine this for command-line argument parsing: 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. +