Skip to content

Instantly share code, notes, and snippets.

@cijogeorge
Last active November 11, 2017 18:53
Show Gist options
  • Select an option

  • Save cijogeorge/640679ebe7c03a77d823b4c79ae6d2c6 to your computer and use it in GitHub Desktop.

Select an option

Save cijogeorge/640679ebe7c03a77d823b4c79ae6d2c6 to your computer and use it in GitHub Desktop.
Fun Scripting Problems with Solutions

Fun scripting problems and their solutions

Note: These code snippets were written and tested in 2008.

FYI: There are some challenging fun problems towards the end. Do check those out.

1. Convert all lower case to upper and vice versa.

tr "[a-z] [A-Z]" "[A-Z] [a-z]" < file

or

#!/usr/bin/perl -w

my @array=<STDIN>;
foreach $line (@array)
{
 $line=~tr/A-Za-z/a-zA-z/;
 print $line;
}

2. Print those lines with PRINT in it.On printing remove all small a.

grep 'PRINT' < file | sed 's/a//'

or

#!/usr/bin/perl -w

my @array=<STDIN>;
foreach $line (@array)
{
 if($line=~/PRINT/)
 {
  $line=~tr/a//d;
  print $line;
 }
}

3. Print only those lines starting with a number and end with a character.

grep "^[0-9].*[A-Za-z]$" temp

or

#!/usr/bin/perl -w

my @array=<STDIN>;
foreach $line (@array)
{
 if($line=~/^[0-9].*[A-Za-z]$/)
 {
  print $line;
 }
}

4. Remove all multiple occurences of a character like aa->a.

sed 's/\(.\)\1*/\1/g' < file

or

#!/usr/bin/perl -w

my @array=<STDIN>;
foreach $line (@array)
{
 $line=~s/(.)\1*/\1/g;
 print $line;
}

5. Remove all multiple occurences of a word with single. eg: ABS ABS->ABS.

sed 's/\(\<[A-Za-z]*\>\)\( \1\)*/\1/g' file

or

#!/usr/bin/perl -w

my @array=<STDIN>;
foreach $line (@array)
{
 $line=~s/(\b[^ ]+\b)(\s\b\1\b)+/\1/g;
 print $line;
}

6. Replace third occurence of word ABS with XYZ.

sed -n '1h;1!{H;};${g;s/ABS/XYZ/3;p;}' file

or

#!/usr/bin/perl -w

@array=<>;
foreach $line (@array)
{
 while($line=~/ABS/g)
 {
  if(++$i==3) {$p=pos($line);substr($line,$p-3,3)='XYZ';}
 }
 print $line,"\n";
}

7. Replace ABC->CED RTY->WWW.

sed '{s/ABC/CED/g;s/RTY/WWW/g;}'

or

#!/usr/bin/perl -w

@array=<>;
foreach $line (@array)
{
 $line=~s/ABC/CED/g;
 $line=~s/RTY/WWW/g;
 print $line;
}

8. If there are 3 lines such tat first line have 'A',second 'B' and third 'C' remove the lines.

sed '/A/ {N; /\n.*B/ { N;/\n.*B.*\n.*C/{s/.*//}}}' file |grep -v "^$"

or

#!/usr/bin/perl -w

@array=<>;
my $size=@array;
my $i=0;
while($i<$size)
{
 if($array[$i]=~/A/)
 {
  if($array[$i+1]=~/B/)
  {
   if($array[$i+2]=~/C/)
   {
    $i+=3;
    next;
   }
  }
 }
 print $array[$i];
 $i++;
}

9. Print all lines except those from 20 to 30.

awk 'NR<20 {print $0} NR>30 {print $0}' file

or

#!/usr/bin/perl -w

@array=<>;
my $size=@array;
my $i=0;
while($i<$size)
{
 if($i<20||$i>30)
 { print $array[$i]; }
 $i++;
}

10. Remove all C comments from a C file.

sed 's/\/\/.*//' filename | tr '\n' '$' |sed 's/\/\*[^\*]*\*\///g' | tr '$' '\n'

11. Remove all blank lines from a file.

grep -v "^$" file > file

or

#!/usr/bin/perl -w

@array=<>;
foreach $line (@array)
{
 if($line!~/^$/)
 {
  print $line;
 }
}

12. Print total number of lines in a file.

cat filename | wc -l

or

#!/usr/bin/perl -w

@array=<>;
my $size=@array;
print $size;

13. Print all lines from the line having MACS to 26th line.

awk '/MACS/,(NR==26) {print $0}' < file

or

#!/usr/bin/perl -w

@array=<>;
my $size=@array;
for($i=0;$i<$size;$i++) 
{
 if($array[$i]=~/MACS/)
 {
  print $array[$i];
  while(++$i<size && $i=26)
  { print $array[$i]; }
 }
}

14. If a line contain MEC enter 'DATA' at the end of the line else enter 'SATA' at the beginning.

awk '/MEC/ {print $0,"DATA";} !/MEC/ {print "SATA",$0;}' filename

or

#!/usr/bin/perl -w

@array=<>;
foreach $line (@array)
{
 chop($line);
 if($line=~/MEC/)
 {print $line."DATA\n";}
 else {print "SATA".$line."\n";}
}

15. If the line contain HI replace all a->b ad b->c and c->d.

sed '/HI/ {y/abc/bcd/;}' filename

or

#!/usr/bin/perl -w

@array=<>;
foreach $line (@array)
{
 if($line=~/HI/)
 {$line=~tr/abc/bcd/;}
 print $line;
}

16. If a file contain word 'XYZ' anywhere in it no matter how many times,print 'Success' once.

awk '/XYZ/ {print "Success";exit;}' < file

or

#!/usr/bin/perl -w

@array=<>;
foreach $line (@array)
{
 if($line=~/XYZ/)
 {print "Success\n"; exit 0;}
}

17. If a file has the word 'ABC' first and somewhere else it has the word XYZ; print success only once.

awk 'BEGIN {a=0;b=0;} /ABC/ {a=1;} /XYZ/ {if(a==1) b=1;} END {if(b==1) print "Success";}' filename

or

#!/usr/bin/perl -w

@array=<>;
foreach $line (@array)
{
 if($line=~/ABC/) {$flag=1;}
 if($line=~/XYZ/ && $flag==1)
 { print "Success\n"; exit 0;}
}

18. Remove all \n from the file.

tr -d "/n" < file > file

or

#!/usr/bin/perl -w

@array=<>;
foreach $line (@array)
{
 chop($line);
 print $line;
}

19. Reverse all lines in a file.

tac file

or

#!/usr/bin/perl -w

@array=<>;
for($i=@array;$i>=0;$i--)
{ print $array[$i]; }

20. Given two unique files. Write a script to find their nearest common parent directory path.

#!/bin/bash

find / -type f -name $1>f
find / -type f -name $2>g
count=`wc -c < f`
for((i=1;i<$count;i++));
do
  read -n$i a <f
  read -n$i b <g
  if [ $a == $b ]
  then
  echo $a > p;
  continue;
  else
  break;
  fi
done
cat p | sed 's/\/[^/]*$/\//'

or

#!/bin/bash

d=1;
find -name $1 -type f > direct1
find -name $2 -type f > direct2
length=$(wc -c < direct.txt)
while [ $d -le $length ]
do   
 char1=`cut -c 1-$d < direct1`;
 char2=`cut -c 1-$d < direct2`;
 if [ $char1 != $char2 ];then
  echo $char1 | sed 's/\/[^/]*$/\//'
  break
  else
  d=`expr $d + 1`
  continue
 fi
done

or

#!/usr/bin/perl -w

my $file1=$ARGV[0];
my $file2=$ARGV[1];
my path;
my $path1=`sudo find / -name $file1 -type f`;
my $path2=`sudo find / -name $file2 -type f`;
my @array1=split //,$path1;
my @array2=split //,$path2;
if(@array1<@array2)
{ $size=@array1; }
else
{ $size=@array2; }
for($i=0;$i<$size;$i++)
{
 if($array1[$i] eq $array2[$i])
 { $path=$path.$array1[$i];}
 else { last; }
}
$path=~s/\/[^\/]*$/\//;
print $path,"\n";

21. Replace all alternate occurances of "printf" with "scanf" in a C code.

awk 'BEGIN{ RS=" "; count=0; } /printf/ { count++; if(count%2==0) { sub(/printf/,"scanf",$0); } } { printf($0" "); }' filename

or

#!/usr/bin/perl -w

@array=<>;
my $x=0;
my $i=0;
foreach $line (@array)
{
 while($line=~/printf/g) 
 {
  if(++$x%2==0)
  {
   push(@ps,pos($line));
  }
 }
 foreach $p (@ps)
 {
  $p=$p-$i;
  substr($line,$p-6,6)='scanf';
  $i++;
 }
 @ps=();
 $i=0;
 print $line; 
}

or

#!/usr/bin/perl -w

while($line=<>)
{
 $count=0;
 $line=~s/printf/++$count%2==0?"scanf":"printf"/eg;
 print $line;
}

22. List all palindromes in a given text file.

#!/bin/bash

exec 0 < 1;
while read or
do
 re=$(echo $or |rev);
 if [ $or == $re ]
 then
 echo $or;
 fi
done

or

#!/usr/bin/perl -w

@array=<>;
foreach $line (@array)
{
 while($line=~/(\w+)\s+/g)
 {
  $var=reverse($1);
  if($var eq $1)
  {print $var,"\n";}
 }
}

23. Given a log file. Find the sum of all numbers appearing in the lines having the word 'REJECT' in it. Also find the no. of such numbers greater than 50.

awk '/REJECT/&&/[0-9]/ {gsub(/[^0-9]+/," ",$0);for(i=1;i<=NF;i++) {sum+=$i; if($i>50) num++;}} END { printf("No. of numbers > 50 : %d \nSum of all numbers : %d\n",num,sum);}' < file

or

#!/usr/bin/perl -w

@array=<>;
foreach $line (@array)
{
 if($line=~/REJECT/)
 {
  while($line=~/([0-9]+)/g)
  { 
   $sum+=$1;
   if($1>50) {$num++;}
  }
 }
}
print $sum,"\n",$num,"\n";

*24. Given a log file. For any lines having the word 'ERROR', print the preceding 2 lines & succeeding 2 lines of the line. Do not do this if the line having the word 'ERROR' also has the word 'FIXED'. Use perl.

#!/usr/bin/perl -w

my $line;
my @array = <STDIN>;
my $i=-1;
foreach $line (@array)
{
 $i++;
 if($line=~m/ERROR/ && $line!~m/FIXED/)
 {
  print $array[$i-2],$array[$i-1],$array[$i+1],$array[$i+2],"\n";
 }
}

25. Given a text file. Convert the file using perl such that the first character of each sentence & first character of each line is capital. All other characters should be small.

#!/usr/bin/perl -w

my @lines = <STDIN>;
my $var;
foreach $var (@lines)
{
$var=lc($var);
if($var=~m/^([a-z])/)
{
 $a=uc($1);
 $var=~s/^[a-z]/$a/;
}
if($var=~m/\.[ ]*([a-z])/)
{
 $b=uc($1);
 $var=~s/(\.[ ]*)[a-z]/\1$b/g;
}
print $var;
}

26. Here's a simple encryption algorithm that you can use to encode secret messages: shift every letter in the message 13 characters towards the end of the alphabet. ("a" becomes "n"; "b" becomes "o"; "x" loops around and becomes "k"; etc.) The beauty of this algorithm is that since the alphabet has 26 letters, you can also decrypt a message by repeating the process and shifting every letter in the message 13 characters towards the end of the alphabet. It's often called "ROT 13" because the algorithm "rotates" each letter 13 places. Write a ROT 13 program that will accept a line of text, print the encrypted message, then decrypt the message and print the result. [Test: does your program work for uppercase and lowercase letters?]

#!/usr/bin/perl -w

@in=<>;
foreach $var (@in)
{
 @array=split(//,$var);
 for($i=0;$i<=$#array;$i++)
 {
  if($array[$i]=~/[A-Z]/)
  {
   $d=ord($array[$i])+13-ord("Z");
   if($d>0) {$w=ord("A")-1+$d;})
   else     {$w=ord($array[$i])+13;}
  }
  elsif($array[$i]=~/[a-z]/)
  {
   $d=ord($array[$i])+13-ord("z");
   if($d>0) {$w=ord("a")-1+$d;}
   else     {$w=ord($array[$i])+13;}
  }
  else {$w=ord($array[$i]);}
  $w=chr($w);
  print $w;
 }
}

27. User provides a date in command line. Print all files that have been modified before that date. Use perl. Assume the script is run in the native folder itself.

#!/usr/bin/perl -w

@array=`ls -l`;
my $m;my $d;my $y;
$date=<STDIN>;
($y,$m,$d)=split(/-/,$date);
$date=$d+31*$m+365*$y;
foreach $line(@array)
{
 @p=split(/\s+/,$line);
 ($y,$m,$d)=split(/-/,$p[5]);
 $d2=$d+31*$m+365*$y;
 if($d2<$date) {print $p[7],"\n";}
 @p=();
}

28. You have current directory containing set of directories which contain files. One file can reside in many directories.Write script which returns number of unique file names inall the subdirectories of the directory.

find . -type f | awk 'BEGIN{FS="/";}{print $NF;}' | sort | uniq

29. List names of all directories in a folder.

ls -F | grep "/$" | sed 's/\(.*\)\//\1/'

30. Delete all blank lines in a file other than the 1st blank line.

awk 'BEGIN{temp=0;} /^$/ {if(temp==0) {temp=1;print;}} !/^$/ {print;}' file

31. Remove text between 2 angular brackets.

sed 's/<[^<]*>/<>/g; s/<[^<]*$/</g; s/^[^>]*>/>/g;' file

32. Increment all numbers in a file by 1.

#!/usr/bin/perl -w

while($line=<>)
{
 if($line=~/[0-9]+/)
 {
  $line=~s/([0-9]+)/$1+1/eg;
 }
 print $line;
}

33. You are given an array of size N that contains positive and negative numbers. Write a program to find the subsequence(contiguous set of elements) with the largest sum. For example, in tthe array -3 -1 5 -3 2 17 -20 -5 9 11 -2, the subsequence with the max sum is 5 -3 2 17 (sum=21).

#include<stdio.h>

main()
{
 int i,j,n,max=0,start=0,end=0;
 printf("Enter the no. of numbers : ");
 scanf("%d",&n);
 int list[n];
 printf("Enter the numbers (separated by 'space') : ");
 for(i=0;i<n;i++)
 {
  scanf("%d",&list[i]);
 }
 for(i=0;i<n;i++)
 {
  int sum=0;
  for(j=i;j<n;j++)
  {
   sum+=list[j];
   if(sum>max)
   {
    max=sum;
    start=i;
    end=j;
   }
  }
 }
 printf("Maximun sum in a substring : %d",max);
 printf("\nSubstring having the maximum sum : ");
 for(i=start;i<=end;i++)
 printf("%d ",list[i]);
 printf("\n");
}

34. You are given a set of lines. A line is identified by x,y co-ordinates of its two end points. Write a program to determine the number of intersections and print all the intersections.

#include<stdio.h>

main()
{
 int n1,n2=0,i,j,count=0,lines[10][2];
 float x1,y1,xx[10],yy[10];
 printf("Enter the no. of lines : ");
 scanf("%d",&n1);
 float x[n1][2];
 float y[n1][2];
 float m[n1];
 float c[n1];
 for(i=0;i<n1;i++)
 {
  printf("Enter x & y coordinates of line %d (separated by 'space'; x1 y1 x2 y2) : ",i+1);
  scanf("%f",&x[i][0]);
  scanf("%f",&y[i][0]);
  scanf("%f",&x[i][1]);
  scanf("%f",&y[i][1]);
  m[i]=(y[i][0]-y[i][1])/(x[i][0]-x[i][1]);
  c[i]=y[i][0]-(m[i]*x[i][0]);
 }
 for(i=0;i<n1-1;i++)
 {
  for(j=i+1;j<n1;j++)
  {
   for(x1=x[j][0];x1<=x[j][1];x1+=0.000001)
   {
    y1=m[j]*x1+c[j];
    if(y1==m[i]*x1+c[i] && x1>=x[i][0] && x1<=x[i][1] && y1>=y[i][0] && y1<=y[i][1])
    {
     xx[n2]=x1;
     yy[n2]=y1;
     lines[n2][0]=i+1;
     lines[n2][1]=j+1;
     n2++;
     count++;
     break;
    }
   }
  }
 }
 printf("No. of intersections : %d",count);
 printf("\nIntersecting lines : ");
 for(i=0;i<n2;i++)
 printf("\nline %d & line %d intersect at point (%f,%f)",lines[i][0],lines[i][1],xx[i],yy[i]);
 printf("\n");
}

35. Given a file with lines having variable length. Modify the file such that each line is 33 characters long (except may be the last line).

sed -n '1h;1!{x;G;x};${x;G;s/\n//g;:a s/\(.\{33\}\)/\1\n/;P;s/\(.*\n\)//;ta}' file

36. Arrange the output of 'ls -ABm' such that each line has 5 fields only.

ls -ABm | awk 'BEGIN{RS=",";count=0;} { sub(/\n/," ",$0); printf($0","); count++; if(count==5) { printf("\n"); count=0; } }'

or

ls -ABm | sed -n '1!g;N;s/\n//g; s/,/,\n/5;P;D;x;'

37. Simulate "find" command using perl without using the perl counterparts for "find".

#!/usr/bin/perl -w

my @options;
my $maxdepth=100;
my $temp=0;
for($i=1;$i<=$#ARGV;$i++)
{
 push(@options,$ARGV[$i]);
}
&find($ARGV[0],0);
sub find
{
 my ($dir,$depth)=($_[0],$_[1]);
 opendir(DIR,$dir) or die "Cannot open directory : $!";
 my @files=grep{$_ ne "." && $_ ne ".."} readdir(DIR);
 closedir(DIR);
 my $file;
 foreach $file (@files)
 {
  my $flag=0;
  my $i;
  my $path=$dir."/".$file;
  for($i=0;$i<$#options;$i+=2)
  {
   if($options[$i] eq "-maxdepth" && $temp==0)
   { $maxdepth=$options[$i+1]; $temp=1;}
   elsif($options[$i] eq "-name")
   {
    if($file!~/$options[$i+1]/) { $flag=1;last; }
   }
   elsif($options[$i] eq "-type")
   {
    if($options[$i+1] eq "f" && -f $path ||
       $options[$i+1] eq "d" && -d $path) {}
    else { $flag=1;last; }
   }
   elsif($options[$i] eq "-perm")
   {
    my $mode=(stat("$path"))[2];
    my $perm=sprintf("%04o",$mode & 07777);
    if($options[$i+1] ne $perm) { $flag=1;last; }
   }
  }
  if($flag==0) { print $path."\n"; }
  if($maxdepth>$depth && -d $path)
  {
   &find($path,$depth+1);
  }
 }
}
#execution : 
#macs@mec:~$ ./fnd ~/macs -name script -type f -perm 0755 -maxdepth 2

#only these options are supported, but others can be added easily.
#any of these options can be used in any order.

38. Simulate 'grep' in perl without using the perl counterpart for 'grep'.

#!/usr/bin/perl -w

my @options;
my @args;
my @array;
my $A_num=0;
my $B_num=0;
my $C_num=0;
my $c=0;
my $n=0;
my $i_=0;
my $o=0;
my $v=0;
my $count=0;
my $before=0;
my $after=0;
my $lastpos=0;
my $pat_flag=0;
my $A_flag=0;
my $B_flag=0;
my $C_flag=0;
for($i=0;$i<=$#ARGV;$i++)
{
 if($ARGV[$i]=~/-e/) { $pat=$ARGV[++$i]; $pat_flag=1; }
 elsif($ARGV[$i]=~/^-/) { push(@options,$ARGV[$i]); }
 else { push(@args,$ARGV[$i]); }
}
for($i=0;$i<=$#options;$i++)
{
 if($options[$i]=~/-A/) { $A_num=shift(@args); $A_flag=1; }
 if($options[$i]=~/-B/) { $B_num=shift(@args); $B_flag=1; }
 if($options[$i]=~/-C/) { $C_num=shift(@args); $C_flag=1; }
 if($options[$i]=~/-c/) { $c=1; }
 if($options[$i]=~/-n/) { $n=1; }
 if($options[$i]=~/-i/) { $i_=1; }
 if($options[$i]=~/-o/) { $o=1; }
 if($options[$i]=~/-v/) { $v=1; }
}
if($pat_flag!=1) { $pat=shift(@args); }
if(@args)
{
 foreach $file (@args)
 {
  open(FILE,"$file") or die "Cannot open file : $!";
  @array=<FILE>;
  close(FILE);
  &match();
 }
}
else
{
 @array=<STDIN>;
 &match();
}
sub match
{
 $lastpos=0;
 for($i=0;$i<=$#array;$i++)
 {
  if( ($array[$i]=~/($pat)/) ||
      ($i_==1 && $array[$i]=~/($pat)/i) ||
      ($v==1 && $array[$i]!~/($pat)/) ||
      ($i_==1 && $v==1 && $array[$i]!~/($pat)/i) )
  {
   $count++;
   if(($before!=0 || $after!=0 ) && $v!=1) { print "--\n"; }
   $before=0;
   $after=0;
   if($A_flag==1 && $C_flag==1 && $A_num<$C_num) { $after=$A_num; }
   elsif($C_flag!=1) { $after=$A_num; }
   elsif($A_flag!=1) { $after=$C_num; }
   else { $after=$C_num; }
   if($B_flag==1 && $C_flag==1 && $B_num<$C_num) { $before=$B_num;}
   elsif($C_flag!=1) { $before=$B_num; }
   elsif($B_flag!=1) { $before=$C_num; }
   else { $before=$C_num; }
   if($c!=1)
   {
    for($j=$i-$before;$j<=$i+$after;$j++)
    {
     if($j>=0 && $j<=$#array)
     {
      if($v==1 && $j<$lastpos) { next; }
      if($before==0 && $after==0 && $#args>0) { print $file.":"; }
      if($n==1)
      {
       my $lineno=$j+1;
       if($o==1) { print $lineno; }
       elsif($v==1) { print $lineno.":"; }
       elsif($before==0 && $after==0 && $#args>0)
       {
        if($array[$j]=~/^#/) { print ":".$lineno.":"; }
        else { print "-".$lineno."-"; }
       }
       else
       {
        if($array[$j]=~/^#/) { print $lineno.":"; }
        else { print $lineno."-"; }
       }
      }
      if($o!=1) { print $array[$j]; }
      else { if($j<$i+$after) { print "-"; } }
     }
    }
   }
   if($o==1)
   {
    if($1) { print ":".$1."\n"; }
   }
  }
  $lastpos=$j;
 }
 if($c==1)
 {
  if($#args>0) { print $file.":" }
  print $count."\n";
 }
 $count=0;
}
#execution :
#mec@macs:~$ ./grp [options]  [PATTERN] [FILE1 FILE2 ..]
#mec@macs:~$ cat FILE | ./grp [options] [PATTERN] 

#checks only perl regex. (though actual 'grep' uses basic regex, no idea how to implement that in perl, coz there's lots of things to be considered)
#options included are -A, -B, -C, -c, -n, -i, -o, -v
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment