summaryrefslogtreecommitdiff
path: root/src/Bash:Lesser_Known_Bits.adoc
blob: 859da71abde70bcac49f24f42b4e70cdaabc744d (plain)
    1 Bash:Lesser Known Bits
    2 ======================
    3 :author: Aaron Ball
    4 :email: nullspoon@iohq.net
    5 
    6 == {doctitle}
    7 
    8 I won't lie, bash is my shell of choice (as if that's not obvious).  Sure, the
    9 ability to handle arrow keys, a command history, colors, and escape sequences
   10 for terminal formatting are all great pieces, but most other shells can do
   11 those things as well. What really makes bash stand out? There's a pretty good
   12 list of things that are lesser known but are super useful, albeit not always
   13 often though. All of these are well documented in the bash man page, but that
   14 one is not exactly easy to find stuff in unless you know what you're looking
   15 for. Running it through the wc command, the bash man page apparently has 41,452
   16 words.  All that aside though, this is a list of some lesser known things I use
   17 occasionally (about once a week-ish) from our friend bash.
   18 
   19 
   20 [[one-liner-loops]]
   21 == One-liner Loops
   22 
   23 This is one that is supported by most if not all of the other shells out there,
   24 but it is still super useful and I don't see it used often. A one-liner loop is
   25 effectively a very short (one line in fact) script used to perform a small
   26 number of operations (it gets confusing if you do too many) in bulk. A good
   27 example here is with a server environment of any size greater than I'd say two.
   28 I frequently need to check lots of servers for something, be it the existence
   29 of a file, the status of a file in comparison with a local copy (diffs), bulk
   30 modifying remote files using sed, etc.
   31 
   32 Recently though, I needed to verify the installed version of sudo
   33 specifically on a list of about 50 servers. I sent the list of servers
   34 to a text file, one server per line, and did the following and had my
   35 answer within about 30 seconds (it takes a few hundred milliseconds for
   36 ssh connections to establish on our atrociou...er...awesome network).
   37 
   38 ----
   39 for i in $(cat ./servers.list); do echo $i; ssh user@$i 'sudo -V | grep "I/O plugin version"'; done
   40 ----
   41 
   42 Presto! A big list of sudo versions across the entire environment.
   43 
   44 
   45 [[process-substitution]]
   46 == Process Substitution
   47 
   48 This one is really great. Some commands require one or more file paths
   49 to do what they need to do. A good example is diff. The diff command
   50 requires two file path parameters: file a and file b. What if you want
   51 to diff the outputs of two remote files though? Using process
   52 substitution, we can cat out a remote file using the typical command,
   53 +ssh user@server 'cat /etc/something'+, and have the output
   54 go to a local temp file for the life of the command calling it so we
   55 have something to work on. For example...
   56 
   57 ----
   58 diff /etc/something <(ssh user@server 'cat /etc/something')
   59 ----
   60 
   61 What we have here is a diff of the local /etc/something file and the remote
   62 /etc/something. The ssh connection string is encapsulated in a +<()+. This is
   63 the process substitution. This doesn't just work with remote files though. Say
   64 for instance you wanted to diff the contents of a directory on a local system
   65 and a remote system. Here's how you'd do that.
   66 
   67 ... or comparing the output of two remote commands...
   68 
   69 ----
   70 diff <(ls -1 /var/log/) <(ssh user@server 'ls -1 /var/log/')
   71 ----
   72 
   73 Here we used process substitution to write the output of +ls -l /var/log+ to a
   74 temp file, then write the output of the same command run on another system over
   75 ssh to yet another temp file, then we use diff as usual to show us what is
   76 different. If you really wanted to get crazy, you could throw this into a bash
   77 one-liner loop and run the diff on multiple systems.
   78 
   79 
   80 [[brace-expansion]]
   81 == Brace Expansion
   82 
   83 Brace expansion is really neat and I think super handy. This is the one I don't
   84 have a lot of use for though. It gets used about once every few scripts or
   85 about once or twice a month. Brace expansion is effectively on-the-fly array
   86 loops for commands. For a simple example, say you wanted to create three
   87 directories: dev, test, and prod. To create these without brace expansion,
   88 you'd have to run _mkdir_ three times. With brace expansion, you can do this
   89 
   90 ----
   91 mkdir {dev,test,prod}
   92 ----
   93 
   94 That's cool, but what's REALLY cool is that you can use this with nested
   95 directories. Say for isntance we are creating a small (and poorly designed) dev
   96 environment. Inside of each we want the directories bin, etc, lib, var (we're
   97 just making 'em up now). Here's how you'd do that in one command
   98 
   99 ----
  100 mkdir {dev,test,prod}/{bin,etc,lib,var}
  101 ----
  102 
  103 That is the equivelant of <syntaxhighlight lang="bash"> mkdir dev/bin
  104 mkdir dev/etc mkdir dev/lib mkdir dev/var mkdir test/bin mkdir test/etc
  105 mkdir test/lib mkdir test/var mkdir prod/bin mkdir prod/etc mkdir
  106 prod/lib mkdir prod/var </syntaxhighlight>
  107 
  108 Another application for this is if you want to cat out a big list of
  109 specific files without catting out the entire directory (I did this one
  110 earlier this morning actually). Say you have 20 files called
  111 *list.<num>* (0-19) and you want to cat out numbers 1-9. Now, there are
  112 a lot of ways to do this of course, but this is how you can do it with
  113 brace expansion.
  114 
  115 ----
  116 cat list.{1,2,3,4,5,6,7,8,9}
  117 ----
  118 
  119 ...or even shorter...
  120 
  121 ----
  122 cat list.{1..9}
  123 ----
  124 
  125 Those are the equivelant of
  126 
  127 ----
  128 cat list.1 list.2 list.3 list.4 list.5 list.6 list.7 list.8 list.9
  129 ----
  130 
  131 How's that for time saving.
  132 
  133 
  134 Category:Bash
  135 Category:Shells
  136 Category:Linux
  137 
  138 
  139 // vim: set syntax=asciidoc:

Generated by cgit