Showing posts with label scripting. Show all posts
Showing posts with label scripting. Show all posts

Monday, March 30, 2009

Magic of perl!

Here is a small script my friend gave me to debug...
Amazing piece of perl regular expression mastery..

perl -e '$i=$ARGV[0];$i++while("."x$i)=~/^(..+?)\1+$/;print"$i\n" _input number_

The output will be the next possible prime number inclusive of the number itself.

for example:
$ perl -e '$i=$ARGV[0];$i++while("."x$i)=~/^(..+?)\1+$/;print"$i\n"' 8
11

$ perl -e '$i=$ARGV[0];$i++while("."x$i)=~/^(..+?)\1+$/;print"$i\n"' 7
7

Each time a number is input the number. A string of "."'s with length equal to the input number is generated.

try:
$ perl -e 'print "."x$ARGV[0]\n;'
To understand what "."x$i does.

$ perl -e 'print "."x$ARGV[0];' 4
....
$

now here is the master piece...
(..+?) matches the smallest possible string of dots (>=2) in the generated string (remember "."x$i) which can be repeated to match the generated string. The ? makes sure that the search is not greedy.

Repetition is achieved by \1+
which says repeat the last matched pattern (\1) at least once (+).
Now smallest possible factoring number is achieved only for non-primes.
Any prime number will not have any string of dots which can be repeated atleast 2 times. Hence the match ("."x$i=~/^(..+?)\1+$/) will fail and while will not increment $i.

So the output will be the next prime number >= the input number.

Who said perl was not powerful? And regular expressions are arcane and cryptic?

Happy scripting!!

Monday, February 23, 2009

Changing Internal Field Separator in a Bash Shell

It took me a long long time to change the IFS (Internal Field Separator) in a bash shell. Which by the way is set as default to whitespace, tab, linefeed and carriage return.

If you want to change it in the shell you have to enter: IFS="whatever you want"
You can view the same using : echo $IFS | cat -vte

My problem was to rename files with spaces in them. As for loop was breaking each file name at space.

So I had to do the following:
# Before you modify your IFS please please please make sure you save your old IFS just in case things do not go as expected. Remember Murphy's Laws are omnipresent!

#IFS=:Space:Tab:Line Feed:Carriage Return:
IFS=$'\x20'$'\x09'$'\x0A'$'\x0D'

Then rename each file.

for f in `ls *.txt`; do
echo $f
# change each file extension from .txt to .csv
mv $f `basename $f .txt`.csv
#Additionally if you want to remove the whitespace too then the following line replaces it with underscore!
# mv $f `basename $f .txt|sed 's/ /_/g'`.csv
done

And done in seconds..
sigh (of relief and happiness)!!!

Happy bashing! :)