Showing posts with label shell. Show all posts
Showing posts with label shell. Show all posts

Wednesday, August 28, 2013

Fun with Bash :: Sums

I frequently find the need to sum up long lists of numbers from the Bash command shell. The following is a nice bit of code that sums up the bytes contained in a series of files and prints out the each sum in GB.

The current directory has files *-bytes.log that each contain a single column with a number of bytes on each row, example:

53824
247104
61776
53824
53824
53824
247104
53824
247104
542

The code contains an outer loop to iterate the files and an inner loop to process the contents of the files
for file in $(ls *-bytes.log); do
  sum=0;
  for num in $(cat $file); do
    let sum=$sum+$num;
  done
  echo "$sum/1024/1024/1024" | bc -l | xargs printf "$file %1.2f GB\n";
done

This is an alternative approach using an inner while loop to read the sums rather than cat'ing the file
for file in $(ls *-bytes.log); do
  sum=0;
  while read num; do
    let sum=$sum+$num;
  done < $file
  echo "$sum/1024/1024/1024" | bc -l | xargs printf "$file %1.2f GB\n";
done

Sample results
user1-bytes.log 3.81 GB
user2-bytes.log 4.75 GB
user3-bytes.log 1.40 GB
user4-bytes.log 2.03 GB
user5-bytes.log 5.01 GB
...

I've also found the following bit of code helpful in my $HOME/.bashrc to make quick calculations easy (this comes from a nixCraft Facebook post:

# nixCraft (on Facebook) calc recipe
# Usage: calc "10+2"
#   Pi:  calc "scale=10; 4*a(1)"
# Temperature: calc "30 * 1.8 + 32"
#              calc "(86 - 32)/1.8"
calc() { echo "$*" | bc -l; }

Wednesday, January 23, 2013

How To: Recursively Create Numeric Directories

I was asked by a colleague how to do the following:

I have a root folder that I need to create a directory based on job numbers.

From the root folder, I'd like to create the following:

1000
1000\1100
1000\1100\1101
1000\1100\1102

all the way up to 

9000\9900\9999

To explain, I'll use the 5000 folder:

I would need:
5000
5000\5100
5000\5100\5101 through 5000\5100\5199
5000\5200
5000\5200\5201 through 5200\5200\5299
and so on.

What would be the easiest way?

The solution isn't a big deal for anyone familiar with scripting, but I figured I'd share here in case other none coders need help with a similar problem.

I wasn't sure whether they were on a Windows computer (figured most likely based on the slashes) or Linux / Mac, so I provided both a Bash and Windows command shell solutions.

There are any number of ways to approach this, I chose nested for loops.

First the Bash solution:

for x in {1..9}; do
  mkdir ${x}000
  cd ${x}000
  for y in {1..9}; do
    mkdir ${x}${y}00
    cd ${x}${y}00
    for ((z=1; z<=99; z+=1)); do
      mkdir `printf "%s%s%02d" $x $y $z`
    done
    cd ..
  done
  cd ..
done

Now the Windows solution:

setlocal EnableDelayedExpansion
for /l %x in (1, 1, 9) do (
  mkdir %x000
  cd %x000
  for /l %y in (1, 1, 9) do (
    mkdir %x%y00
    cd %x%y00
    for /l %z in (1, 1, 99) do (
      if %z LSS 10 (
        mkdir %x%y0%z
      ) else (
        mkdir %x%y%z
      )
    )
    cd ..
  )
  cd ..  
)