Bash Cookbook

Bash Cookbook

I’ve been slowly making my way through O’Reilly’s Bash Cookbook: Solutions and Examples for Bash Users, 2nd edition, by Carl Albing & JP Vossen. It’s a great book but is enormous and not really structured for reading from beginning to end, as much as for referring to to solve a specific problem. I doubt I will ever finish it.  But, there are a lot of great factoids in there!  Last year, I read Packt’s Mastering Embedded Linux Programming, second edition, by Chris Simmonds, as well as Embedded Linux Development Using Yocto Project, second edition, by Alex Gonzalez (both of which I should do reviews on), and picked up a few of the commands I mention below in those books.

I learned Unix shell commands first on a DEC Vax 11-780 starting about 1984 at college, and then more over time using various distros of Linux from maybe 1997 onward. I’ll admit that most of what I know about ‘sh’ and ‘bash’ are from long ago.

Of course, time does not stand still, and though much of what I learned way back in the 1980s still applies, there is a lot that is new. Here are some cool examples of bash, GNU, and Ubuntu command line programs, as well as useful shell syntax, that I’ve picked up lately:

  • lsb_release
    Find out which release of Ubuntu you are on:

    $ lsb_release -sc
    $ lsb_release -a
    No LSB modules are available.
    Distributor ID:    Ubuntu
    Description:    Ubuntu 18.04.3 LTS
    Release:    18.04
    Codename:    bionic
  • uname
    Find out exactly what Linux kernel you’re running (without having to dig through ‘dmesg’):

    $ uname -a
    Linux Pallas 5.0.0-27-generic #28~18.04.1-Ubuntu SMP Thu Aug 22 03:00:32 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
  • lastb
    See when (and/or if) anyone else has recently tried and failed to log in to your box.
  • lsusb, lsblk, lsof, lshw, lsipc, lsmem, lsattr, lslocks, lspci, …
    There are a number of super helpful commands to find out more about USB devices, block devices, open files, hardware, etc.  sometimes ‘sudo’ is needed to get a full picture.
  • htop
    Show information (similar to ‘top’) for all processes, but also show a pseudo-graphical CPU load graph per CPU core, as well as color-coding to make it more readable…
  • type
    Searches your environment (including aliases, keywords, the path) for a command; -a shows all matches:

     $ type -a ls
     ls is aliased to `ls --color=auto'
     ls is /bin/ls
  • which
    Similar to type, but only searches the path:

    $ which ls
  • apropos
    Searches man pages for a regular expression; helpful if you forget the exact name of a command:

    $ apropos games
     intro (6)            - introduction to games
     sol (6)              - a collection of card games which are easy to play with the aid of a mouse.
  • locate
    Searches a database about the system (which is updated by a cron job):

     $ locate grub.cfg
  • stat
    Get very detailed information about a file:

     $ stat /boot/grub/grub.cfg
     File: /boot/grub/grub.cfg
     Size: 10542         Blocks: 24         IO Block: 4096   regular file
     Device: 805h/2053d    Inode: 2097154     Links: 1
     Access: (0444/-r--r--r--)  Uid: (    0/    root)   Gid: (    0/    root)
     Access: 2019-09-11 11:28:16.269000000 -0700
     Modify: 2019-09-10 10:13:49.739865322 -0700
     Change: 2019-09-10 10:13:49.751865322 -0700
     Birth: -
  • printf
    There’s a command line (or scriptable) printf?  Who knew?

    $ printf '%s = %d\n' Columns $COLUMNS
     Columns = 157
  • redirecting stdout and stderr

    'command &> file' or 'command >& file' 

    are simpler ways to do the old syntax:

     'command > file 2>&1'

    All these will redirect both stdout and stderr to the file.

  • redirecting output from multiple commands to the same file

     '{ cmd1; cmd2; cmd3; ... cmdN; } > file' 


     '(cmd1; cmd2; cmd3; ... cmdN) > file'

    will redirect all output from each command to the same file.  In the past I have resorted to placing multiple commands in a shell script, then running that and redirecting its output.  Now I know better!
    Note that using parentheses actually cause the commands to run in a subshell, so if they modify the environment, any changes will be lost in the current shell.  Braces, however, run in the current shell.

  • alternate way to pass arguments to a command from another
    I’m familiar with the old backtick (`) way to run a command and have the result of that be an argument to another command:

    rm `find . -name '*.bak'`

    but there is a more modern way which is nestable:

    rm $(find . -name '*.bak')
  • more to come…