Bash Loops for one liners

So you have your bash one liner all done and ready to go may be with a little help from commandlinefu.com or from Peteris Krumins’ blog . Here is an example that outputs a csv line of your external host name/ip address pair.

     curl -s ifconfig.me/all | perl -alne '$ip=$1 if /ip_addr: (.*)/; $host=$1 if /host: (.*)/; END {printf("%s,%s\n", $host,$ip)}'
    

Here we are using Perl with “-plane” options which is very powerful. Specifically the options are:

-n: To operate on each line.
-p: Same as n, but also print the line
-l: To automatically strip new line and add it when printing.
-a: To automatically cut each line by white space and put them in $F variables.
-e: To execute the perl code.

You can also make use of special Perl variables like $_ for the current line and $. for the current line number. So not to digress further, we want this one liner to executed in loop like across several hosts.

Loop with predefined set of values

The easiest way is to run with a predefined set of values like this:

     for host in a b c; do oneliner.sh; done
    

Now your oneliner can have issues with STDERR and that can mess up your csv that you are trying to generate, to fix this you can redirect STDERR to /dev/null.

     for host in a b c; do oneliner.sh 2>/dev/null; done
    

If you are doing ‘ssh’ in your oneliner to execute a command, you need to to use the “-n” option or read for /dev/null for the loop to not hang.

     for host in a b c; do ssh $host df -k . < /dev/null; done
            or
     for host in a b c; do ssh -n $host df -k . ; done
    

Loop by executing a command

You can loop by executing a command that produces a line that need to be executed inside the loop. It should probaly look like this:

     for i in `ls -1`; do oneliner.sh $i; done
    

You can use same “2 > /dev/null” trick to avoid erroneous output.

Loop around a count

If you loop run a loop around for a certain numeric range, you can use “seq” command. This command can also takes step as an argument and count forward or backward. For generating random data, there is also ‘jot’ command.

    for i in  `seq -f "%02g" 2`; do ssh myhost$i "ls"; done
    

Loop forever

You can use the while construct to loop forever. You might find any use for it, but there is really good one. For example, you have a tmux pane dedicated to remote logging on to a host and the connection gets terminated due to your network coming in and out due to your VPN or Computer sleep, you can use this following variation, where you just need to enter on your keyboard to reconnect.

    while :; do ssh myhost; echo disconnected; read input; done
    

The ‘read input’ basically waits for your enter command so that it does not keep trying to reconnect over and over again.

Loop from input from previous command.

The while construct can also be used when your input comes from a previous command on the pipe.

    some line (like curl that lists hosts) | while read line; do ping -c 1 $line; done 
    

I am sure there are more ways you can do loops, so let me know if you find some interesting ones.