Sunday, July 27, 2008

Zero in front

I wrote this one when I was using the KDE default picture viewer thingie, I forget what it's called. Anyway, I had files with names starting with numbers: 1-joe-sans-pants.png, ..., 10-joe-with-undrwr-on-head.png, etc. and the program had trouble sorting them properly.

It did lexicographical sorting instread of numeric - this means that the numbers from 1 to 20 were sorted like this:
1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 2, 20, ...
... you get the idea - and I just wanted them to be sorted like from lowest to highest number...

So, what this script does, is rename files, so that both types of sorting produce same results, i.e. prefixes the name with zeros. And that's it.

I actually did some work on this script before uploading it, because it didn't use to be so universal, i.e. it only handled up to three digits and worked only on the local file - now it's much more versatile, and, unfortunately much slower...

And here it is:
#!/bin/bash
#
# Zero in front
# Renames all files which start with digits, 
# padding them with 0s, to get the length of the numbers equal,
#
# Potential issues:
#   This script will overwrite existing files
# Parameters:
10#   a list of directories subject to conversion, or
11#   no parameters to convert files in current directory.
12# Requires:
13#   nothing
14# Author:
15#   Konrad Siek 
16
17# Scans directory.
18# @param $1: directory
19function scan_directory {
20    # See how long is the largest number
21    top_rank=`expr $(ls $1 | sort -nr | head -n1) : "^[0-9]*"`
22    
23    # If there's anything to do at all...
24    if [ $top_rank -gt 0 ]
25    then
26        # Cycle through the files in the directory...
27        for file in `ls $1`
28        do
29            # Check the length of the current number
30            # This is what takes so much time, it seems...
31            this_rank=`expr $file : "^[0-9]*"`;
32
33            # Act only if there is a number in front
34            if [ $top_rank -gt $this_rank ]
35            then
36                # Create a padding prefix - pad with 0s
37                padding=""
38                for i in $(seq 0 $(expr $top_rank - $this_rank - 1))
39                do
40                    padding=$padding"0"
41                done                
42
43                # Actually move the files
44                mv $1/$file $1/$padding$file
45            fi
46        done
47    fi
48}
49
50# Main
51if [ $# -gt 0 ]
52then
53    # If directories specified, scan each of them separatelly
54    for directory in $@
55    do
56        scan_directory $directory
57    done    
58else
59    # If no arguments, then use this directory
60    scan_directory `pwd`
61fi


The code is also available at GitHub as bash/zero_in_front.

No comments: