Posts Tagged ‘seq’

2012w09

Sunday, March 4th, 2012

Ohai!

This week has been rather productive. I’ve both gotten work done AND learnt a crapload of stuff AND gotten to hack away on some scripts, leading to some personal programming revelations :D

When it comes to shell scripting, printf has become a new friend (leaving echo pretty much out in the cold). It is a continuation from last weeks post about shell tricks and I actually got to use it helping a colleague at work to better format the output of a script.

Something along the lines of:

printf "There were %s connections from %s\n" `some-counting-command` $tmpIP

I also wrote a small demonstrator for another colleague:

for i in `seq 1 21`; do printf "obase=16; $i\n" | bc; done

(Yes, I know about printf’s ability to convert/print hexadecimal on the fly)

for i in `seq 1 21`; do printf "%0.2x\n" $i; done

The for loop piping to bc was mostly for fun and to spark ideas about loops and pipes.

In another script I found myself needing two things: a reliable way to shut the script down (it was running a loop which would only stop when certain things appeared in a log) and a way to debug certain parts of the loop.

I know there is nothing special at all about it, but coming up with the solution instead of trying to google myself to a solution left me feeling like a rocket-scientist ;D

If you have a loop, and you want the ability to controllably get out of said loop, do something along the lines of this in your script:

touch /tmp/someUniqueName
while [ ... && -f /tmp/someUniqueName ]; do 
    ...
done

My first thought was to use $$ or $! to have a unique name but since I wouldn’t (couldn’t) be running more than one instance of this script at a time, I didn’t need to worry about that, and it would have made it a tiny bit harder to stop the script, so I finally (thanks razor) opted for a static, known, filename.

While that file exists, and you other loop conditions are normal, the loop will … loop on, but the second either condition becomes false, like someone removing the file ;) the loop doesn’t do another iteration.

Problem two was that I wanted a quick way to switch between running the script live, or in debug mode. Since running it live calls on some other stuff which then takes a while to reset, debugging the script using these calls would have been painfully slow, but I found a neat way around that:

DEBUG="echo" # (should be "" (debug off) or "echo" (debug on)
...
$DEBUG some-slow-command
...

With debug “on” it will print the command and any parameters, instead of executing it. It doesn’t look all that impressive in this shortened example, but instead imagine if you had more than ten of those places you wanted to debug.

What would you rather do? Edit the code in ten+ places, perhaps missing one, or just change in one place, and have it applied in all the places at once?

This script, once in place and running, did however bring with it another effect, namely a whole lot of cleanup. Cleanup which could only be performed by running a command and giving it some parameters, which could be found in the output of yet another command.

To make matters worse, not all lines of that output were things I wanted to remove. The format of that output was along the lines of:

<headline1>,<date>
<subheader1-1>,<date>
<subheader1-2>,<date>
<subheader1-3>,<date>
<subheader1-4>,<date>
...

<headline2>,<date>
<subheader2-1>,<date>
<subheader2-2>,<date>
<subheader2-3>,<date>
<subheader2-4>,<date>
...

<headline3>,<date>
<subheader3-1>,<date>
<subheader3-2>,<date>
<subheader3-3>,<date>
<subheader3-4>,<date>
...

Again, these seem like small amounts, but for the “headline” I needed to clean up, there were about 70 subheaders, out of which I wanted to clean up all but one. Thankfully, that one subheader I wanted to preserve was not named in the same way as the other 69 subheaders (which had been created programmatically using the loop above).

Also, it was rather important not to delete any other headlines or subheaders. awk to the rescue! But first, here are some facts going into this problem:

  • the subheaders I wanted removed all shared a common part of name between each section is an empty line
  • I knew the name of the section heading containing the subheaders to remove
  • To remove one such subheader I’d need to execute a command giving the subheader as an argument

And this is what I did:

list-generating-command | awk -F, 
    '/headline2/ { m = 1 }
    /subheader/ && m == 1 { print $1 }
    /^$/ { m = 0 }' | while read name;
do
    delete-subheader-command $name
done

Basically, what is going on here is that first of all, setting the field separator to “,” and then, once we come across the unique headline string, set a little flag telling awk that we are within the matching area, and if it can only match the subheader pattern, it gets to print the first column of that line. Finally, when we reach any line containing nothing but a newline, unset the flag, so that there will be no more printouts

And another thing I’ve stumbled upon, and which I already know where I can use this, is this post and more specifically:

diff -u .bashrc <(ssh remote cat .bashrc)

(although it is not .bashrc files I am going to compare).

And finally, some links on assorted topics: