Bash for beginners

Page content


  • It strips paths from filenames:
    • $ >> basename <dir>/<file_name.ext> % <file_name.ext>
  • It can also strip a suffix (e.g., extension):
    • $ >> basename -s <.ext> <dir>/<filename.ext> % <file_name>

Command-Line Arguments

$ >> nano

echo "script name: $0"
echo "first arg: $1"

$ >> bash arg1 % script name: % first arg: arg1

  • You can define the number of args using $#. It does not count the script name, $0 as an argument.

$ >> nano


if [ "$#" -lt 3 ] # are there less than 3 arguments? 
    echo "error: too few arguments, you provided $#, 3 required"
    echo "usage: arg1 arg2 arg3"
    exit 1
echo "script name: $0"
echo "first arg: $1"
echo "second arg: $2"
echo "third arg: $3" '

$ >> bash arg1 arg2

% error: too few arguments, you provided 2, 3 required % usage: arg1 arg2 arg3



set -e
set -u
set -o pipefail

if [<command>] then

File and directory test expressions

File/directory expression Description
-d dir dir is a directory
-f file file is a file
-e file file exists
-h link link is a link
-r file file is readable
-w file file is writable
-x file file is executable
set -e
set -u
set -o pipefail

if [ -f <file_name> ]
then <if_statement>

Curly Braces in Bash

Array Builder

  • {0..10} := 0 1 2 3 4 5 6 7 8 9 10
  • {10..0} := 10 9 8 7 6 5 4 3 2 1 0
  • {10..0..2} := 10 8 6 4 2 0
  • {a..z} := a b c d e f g h i j k l m n o p q r s t u v w x y z
  • You can use these in your scripts:
    • i.e. $ >> touch {1..3}.txt creates 1.txt, 2.txt, 3.txt files.

Exit Codes

  • 0 OK
  • 1 if minor problems (e.g., cannot access subdirectory)
  • 2 if serious trouble (e.g., cannot access command-line argument)

File Descriptors

| File            | C identifier | File descriptor | Defaults to           |
| --------------- | ------------ | --------------- | --------------------- |
| Standard input  | stdin        | 0               | data fed into program |
| Standard output | stdout       | 1               | terminal              |
| Standard error  | stderr       | 2               | terminal              |

stdin (0) -> program -> stdout (1)
                     -> stderr (2)


  • >/dev/null redirects the command standard output to the null device that discards the information written to it.
  • 2>&1 redirects the standard error stream (2) to the standard output stream (1). Note that this takes the standard error stream and points it to the same location as the standard output at that moment. This is the reason for the order >/some/where 2>&1 because one needs to first point stdout to somewhere and then point stderr to the same location if one wants to combine both streams in the end.
  • To save errors to a file:
    • $ >> <bash_command> 2> <error_file.txt>
  • To save output and error messages into the same file:
    • $ >> <bash_command> > <output_file_name> 2>&1

A robust Bash header

    set -e # tells the script to terminate if any command exited with a nonzero exit status.
    set -u # tells the script not to run any command containing a reference to an unset variable name
    set -o pipefail # to cover one of the exceptions of `set -e`: if the last program terminates with a nonzero status, the pipe will not be terminated.


  • UNIX provides different flavours of shells:
    • Bourne shell (sh)
    • C shell (csh)
    • TC shell (tcsh)
    • Korn shell (ksh)
    • Bourne Again shell (bash)
  • $ >> echo $SHELL # prints the default shell.
  • $ >> echo $0 # prints the current shell.


  • shuf --help for detailed information.
  • There are three ways to use the shuf command:

1. file shuf

  • It generates random permutations from input lines to standard output.
  • If given a file or series of files, it will shuffle the lines and write the result to standard output.
  • shuf <file_name>
  • Pick a random line(s) from a file shuf -n <number_of_line(s)_to_be_selected> <file_name>

2. list shuf

  • shuf -e <space_separated_list>
  • Pick a random element(s) from a list shuf -n <number_of_element(s)_to_be_selected> -e <space_separated_list>

3. range shuf

  • shuf -i <start_index>-<end_index> # it shuffles the numbers between <start_index> <end_index>
  • shuf -i <start_index>-<end_index> -n <number_of_number(s)_to_be_selected> # it picks <number_of_number(s)_to_be_selected> number(s) between <start_index> <end_index>


  • They don’t have data types, but it is helpful to think as strings.
echo ${results_dir}

Writing Pipes

  • A pipeline is a sequence of one or more commands separated by one of the control operators ‘|’ or ‘|&’.
  • If ‘|&’ is used, the command’s standard error, in addition to its standard output, is connected to the next command’s standard input through the pipe; it is shorthand for 2>&1 |.


  • It reads data from standard input (stdin) and executes the command one or more times based on the input read. $ >> xargs # == echo.

xargs with another command

  • It is extremely useful when combined with other commands. e.g., find and grep. $ >> xargs find . -name # waits for the input until Ctrl+D tell xargs that we are done with the input.
  • Any blanks and spaces in the input are treated as delimiters, while blank lines are ignored.

Making xargs execute command multiple times

  • -L parameter requires a number which it treats as the maximum line of non-blank lines that should be passed as input to the command at one time.
    • $ >> xargs find . -name -L 1 # to give all inputs as a single line in a way that find command accepts.
  • -n parameter requires a number that would represent the number of arguments that you want xargs to pass per command line.

Handling filenames with spaces

  • -d '<delimiter>' changes the delimiter.

Handling filenames with newline characters

  • $ >> find . -name "<wildcard>" -print0 | xargs -0 gedit
  • print0 prints the full file name on the standard output. It allows file names that contain new lines.

Finding files containing a specific text

  • $ >> find . -name "<wildcard>" | xargs grep "<searching_word>"

Accepting input from a file

  • -a expects a file name.
  • $ >> xargs -a <input_file_name> ls -lart

Seeking user permission before executing a command

  • -p asks for permission each time it runs the command.


  • MacOS installation: brew install yarn
  • yarn is a more convenient, safer and faster package dependency manager that can be used instead of npm in JS projects.
  • To use yarn in your current npm project, simply run yarn in your project directory.
  • Switching to yarn by npm is easy because it works with the same package.json format.
  • When you run the yarn add <package name> code to install packages in the project directory, it will create the yarn.lock file in the project directory.
  • yarn create <pkg_name> <dir_name_to_put_app_there>