Bash

Most of this comes from the excellent guide to bash : Bash Academy

Bash is a shell program written to listen for commands from users and execute them. There are other shell programs (C shell, Z shell, Korn shell, etc.).

Bash uses text-based interface to interact with the users. It takes input (Std In) as text and displays output (Std Out) and error (Std Err) as text using a terminal emulator program.

Bash can be used interactively in the terminal emulator or non-interactively as a written script of commands that is executed.

When bash starts a program, the system creates a running process for it. Bash creates file descriptors and connects them to the same streams as it's own : (keyboard to FD:0 (input) and FD:1 (output) and FD:2 (error) to display 0). The pipe | is vastly used syntax sugar to connect the output of a command to the input of another.

Bash has synchronous command execution meaning it will execute commands one at a time and users cannot interact with bash while it is executing a command.

Bash is not a strict interpreter. The discipline of writing clear, safe and precise code lies heavily upon the user.

Don't write bad bash code.

Bash commands tell bash to perform a certain unit of work. These units of work cannot be subdivided: bash needs to know the whole command to be able to execute it.

There are different kinds of commands for different types of operations. Some commands group other commands into blocks or test their result.

Many command types are syntax sugar: their effect can be achieved differently, but they exist to make the job easier.

Basic commands

Every command has a name that tells bash what to do.

Bash performs a search using this name and looks for :

  • alias (first)
  • functions
  • built-in commands
  • programs installed (searches through PATH, also called external command)

Bash outputs an error if the command was not found.

echo

Displays target on standard output.

Example

$ name=john
$ echo name
name
$ echo $name
john

Compound commands

Compound Commands compound a certain number of basic commands into a larger logical block.

If blocks

Execute commands according to conditional results

$ read -p "Name ? " name
Name ? Some Name
$ if [[ $name = $USER ]]; then
> echo "Hello, $USER."
> else
> echo "Hello, $name."
> fi
Hello, Some Name.

Control Operators

|| OR operator

This control operator tells bash to run a second command only if the first command before it failed. If the first command doesn't fail, the second command is entirely skipped.

This is useful for showing error messages when commands fail.

Example

$ rm hello.txt || echo "Could not find file."
rm: cannot remove 'hello.txt': No such file or directory
Could not find file.

Arguments are a sequence of characters considered as a single unit by the shell.

They can be a filename, a variable name, the name of a program or just a litteral.

Quoting vs Escaping

Quoting is the act of wrapping the argument using '' and “”.

Escaping is the act of adding a single \ before the character we want to escape.

Quoting is a better practice than escaping and should be use more often than not. Quoting is sometimes unnecessary but it is rarely wrong to quote.

If there is whitespace or a symbol in your argument, you must quote it.

  • Use “double quotes” for arguments that contain expansions (such as \$variable or $(command) expansions)
  • Use 'single quotes' for any other argument

'Single quotes' forces the entire quote to remain literal. “Double quotes” still allow some bash syntax.

Quotes are sometimes not necessary, but you can still quote to be safe.

Example of a major bash error due to lack of quoting

Pathname expansion

Expansion is the practice of replacing a part of our command code with a situationally specific piece of code.

In other words, we use expansion to build generic commands that adapt to different situations by expanding a part of our command, hereby replacing it with what the specific situation requires.

Expansion is always performed by bash itself, and always before actually running the command!

$ rm -v *
#The rm command will not see the * expansion.
#It will be given a list of all files in the current directory

Globs/Meanings

*

A star or asterix matches any kind of text, even no text at all.


?

A question mark matches any one single character.


[characters]

A set of characters within rectangular braces matches a single character, only if it's in the given set.


[[:classname:]]

When there is a set of colons directly inside the rectangular braces, you can specify the name of a class of characters instead of having to enumerate each character yourself.

Bash knows about various kinds of character classes. For example, if you use the [ [ :alnum: ] ] pattern, bash will match it against a character only if it is alphanumeric. Supported character classes include: alnum, alpha, ascii, blank, cntrl, digit, graph, lower, print, punct, space, upper, word, xdigit


Globs don't jump into subdirectories. Use globs in path names to expand to multiple directories

Extended Globs

We can access extended globs in a current shell using

$ shopt -s extglob

See here for more explanations on using them

Tilde expansion

Tilde expansion happens earlier in the parser phrase, and is different from pathname expansion.

It is always replaced by an explicit pathname pointing to the home directory of the user or of another user explicitly named after the tilde.

$ echo 'I live in : ' ~
I live in : /home/mh
 
$ echo ~root
/var/root

Command expansions are a very useful value expansion example. You can call a command within a command by using $(…) syntax.

$ echo 'Hello world.' > hello.txt
$ cat hello.txt
Hello world.
$ echo "The file <hello.txt> contains: $(cat hello.txt)"
The file <hello.txt> contains: Hello world.

You must always use “double-quotes” when using value expansions or the $ sign will be output as a literal between 'single quotes'

By default, new commands inherit the shell's current file descriptors. We can use redirections to change where a command's input comes from and where its output should go to.

Redirect to different files

$ ls -l >myfiles.ls 2>/dev/null
 
#We redirect FD 1 to the file "myfiles.ls"
#and FD 2 to /dev/null
 
 
                 ╭──────────╮
    Keyboard ╾┬─╼┥0  bash  1┝╾─┬─╼ Display
              │  │         2┝╾─┘
              │  ╰─────┬────╯
              │        ╎
              │  ╭─────┴────╮
              └─╼┥0  ls    1┝╾───╼ myfiles.ls
                 │         2┝╾───╼ /dev/null
                 ╰──────────╯       

Redirect to one file

$ ls -l a b >myfiles.ls 2>&1
#Make FD 2 write to where FD 1 is writing
 
 
                 ╭──────────╮
    Keyboard ╾┬─╼┥0  bash  1┝╾─┬─╼ Display
              │  │         2┝╾─┘
              │  ╰─────┬────╯
              │        ╎
              │  ╭─────┴────╮
              └─╼┥0  ls    1┝╾─┬─╼ myfiles.ls
                 │         2┝╾─┘
                 ╰──────────╯

Duplicating file descriptors, otherwise referred to as “copying” file descriptors, is the act of copying one file descriptor's stream connection to another file descriptor.

As a result, both file descriptors are connected to the same stream.

Order matters !

#These are not the same :
$ ls -l a b 2>&1 >myfiles.ls #Broken !
$ ls -l a b >myfiles.ls 2>&1 #Correct

For convenience :

#This convenience sugar syntax exists for directing both FD1 & FD2 to the same location
$ping 127.0.0.1 &>results

Append to a file

Use double brackets :

echo Hello >~/myfile
echo World >>~/myfile

Hashbangs

To make a script out of a file containing bash commands, add a hashbang at the beginning of the file :

This is a direct path to bash in many GNU/Linux distributions

#!/bin/bash 

This invokes the 'env' program giving bash as an argument explicitly asking 'env' to find the path to bash and return it. It is safer and more inclusive for covering more exotic distributions and other operating systems.

#!/usr/bin/env bash

The script must be made executable before being run

$ chmod +x my_script.txt
$ ./my_script.txt

Note : the “.” means “current directory”

Command names with a slash are always considered direct pathnames to the program to execute.

  • linux/bash.txt
  • Last modified: 2020/06/01 16:35
  • (external edit)