Sometimes you just need to get stuff done quickly and there’s nary a replacement better than a quick shell one-liner. Recently I’ve needed to feed some large, multi-variable commands into an external program for processing. Here’s some simple shell one-liners and loops that have helped me along the way.

Starting Small – Simple For Loops
At the base of all iterative loops is the for loop. I’m not going to go into too much detail because it’s documented extensively everywhere much better than I will be able to explain it here. It still warrants basic explanation for folks starting out however.

At its most simple construct we have:

forname [inword ...] dolistdone

You’re saying for every name or variable in some action do something. Here’s a practical example using sequential numbers and echo.

for x in $(seq 0 2); do echo $x; done
0
1
2

Above, we designated the variable x to signify an iterative numeric range between 0 and 2 using the seq command and perform the action of echo on each one of the numbers in that range.

Let’s look at another using an external file: /tmp/people. This will contain a single list of names, one on each line.

cat /tmp/people
jane
fred
antoine
marek
bubba

We will now use a for loop to echo this into an English sentence.

for people in $(cat /tmp/people); do echo "$people is my friend."; done
jane is a friend.
fred is a friend.
antoine is a friend.
marek is a friend.
bubba is a friend.

For Loops with Multiple Variables
Let’s look at some more advanced usage that fits more into real-world examples. I need to create a for loop iterating through a file containing two different sets of variables: MAC addresses and their corresponding hostnames.

In this example I am trying to run a series of Foreman commands to create host entries (IP/DNS entries, DHCP records) for a set of new machines. I certainly don’t want to do this by hand or in a web UI so I’ll use the Foreman Hammer CLI command.

Here’s the file I want to operate on containing two columns: MAC address and hostname and I want to pass line1 column A along with line1 column B for each command and so on. There are a lot here so I’ll just show you a few to understand the structure.

Let’s break this down by the numbers: we are sending the stream of our file /tmp/hosts line by line to a pipe and reading it. We assign mac for column1 line1 and hostname for column2 line1 above. We can then refer to these variables to complete the rest of our commands.

Logical OR Comparisons
Using the shell built-in || operator you can have a command execute only if the first command has a non-zero exit status or fails. This is infinitely useful in one-liners. Here’s an example where I want to print SUCCESS/FAIL of pinging a handful of servers:

Loop Counts
You can create an ordered loop that starts and ends based on predefined range or a number of files or targets present (or really anything measurable). Here’s an example:

We will create a 9 files called document1 through document9

for x in $(seq 1 9); do touch document$x; done

Now let’s print an arbitrary label of “File” next to each file using a loop count (the total amount of items is the number of files in this directory. We will the * glob character to include any item in the current directory.

Infinite Loops
You can take this a step further and create an infinite loop, stopping it with control + c. This might be useful if you want to run a repeating command to ensure a machine is alive or set some sort of a quick and dirty timer, it simply iterates from 1 and echoes the number every 10 seconds.

When It’s Too Much?
Usually if I have to stop to debug several layers of pipes, awk, sed and double and single quotes it’s time to just use Ansible or Python. While it’s cool to show off a particularly sick masterpiece of a regex one-liner the question you should be asking is am I saving time? I believe you can do almost anything in shell but should you really?

An example might be copying large sets of SSH public keys in an ad-hoc fashion to many servers. For me the best way to do this is with the Ansible SSH module but sometimes I’ll do this with a Python tool if it’s a one-off situation. You can do this in a one-liner but it may become too much to manage, and really you should use config management for this sort of stuff anyway.

Extending Further
This is just a very small set of examples. I keep my miscellaneous scripts on Github but there’s always a time to use one-liners to accomplish tasks. You might also take a look here or at any of the manymany shell scripting examples and guides on the internet for more ideas.

Do you have some favorite shell one-liners? Let me know in the comments and I’ll be happy to add them here.

Sep 20, 2017 sadsfae commented on issue redhat-performance/quads#133 Hey @bengland2 yes, we use both clearpart and zerombr, e.g. zerombr clearpart --all --initlabel I think that Anaconda should have no problem clear…

Sep 19, 2017 sadsfae commented on issue redhat-performance/quads#133 Update here, we believe this is a bug in Anaconda and have retrieved logs from a failed deployment that had LVM cruft on the disks. The following w…