Bash Script to Batch Resize all Images in a Folder

A simple script which will recognize all image types in the PWD and reduce them by 50% and copy them to the resized folder under PWD. Good for bulk resizing of images.

#!/bin/bash
files=($(file -i * | awk -F ':' 'BEGIN {ORS=""} /^.*:[ \t]*image\/[a-z]*; charset=binary/ {for(i=1;i<NF-1;i++) {print $i":"} {print $(NF-1)"\n"} }' | sed 's/ /:spacecharacter:/g' | tr '\n' ' '))
echo ${files[@]}
mkdir -p resized
for file in ${files[@]}
do
  file=$(echo $file | sed 's/:spacecharacter:/ /')
  convert -resize 50% "$file" resized/"$file"
  #You can use mogrify instead of resize if you want to edit the images in place.
  #mogrify -resize 50% "$file"
done

Copy the script to ~/bin directory and make it executable chmod +x resize_images. Change into the directory containing the images and execute the script.

Useful Bash Variables

Everytime I write a bash script, I have to look up one of these special bash variables and I always forget which one is which. Jotting it down so that I don’t have to google for them the next time.

  • $@ – all arguments as a big string.
  • $# – number of arguments passed in
  • $? – exit code of the last program
  • $$ – your process ID
  • $! – process ID of last program started w/ ‘&’

Javascript: missing } in XML expression

There are some issues which are almost impossible to debug, but when you spot whats wrong, you feel incredibly stupid. This was one of those errors.

Got this error, when I copy-pasted javascript code from the <head> of an HTML document and spent close to half an hour figuring out what was wrong. So what was wrong? Well I forgot to strip the <script></script> tags from the Javascript that I copied!

Redirect / Log the Output of a Bash Shell Script from within the Script

It is a common practice to use 1>/dev/null 2>&1 after commands to suppress any kind of output completely. The same technique is also used to redirect the output to a text file for logging purposes instead of /dev/null. For eg.

echo "hello" 1>/tmp/hellolog 2>&1

However if you are writing a rather long bash script, it is frustrating to add that at the end of every command whose output you want logged. It would be convenient to have one single setting, so that any output produced by the commands within the script is redirected to a log file. Well surprisingly, its extremely simple to setup your script for the above functionality. All you need is an extra line of code at the top of your bash file.

exec &>/tmp/log

If you have the above line in your script, all output (STDOUT and STDERR) will be redirected to /tmp/log. So the first eg. of the echo command can also be written as:

#!/bin/bash
exec &>/tmp/hellolog
echo "hello"

Infact the construct &>/tmp/log is equivalent to 1>/tmp/log 2>&1 and can be used interchangeably. &>/tmp/log would create a new /tmp/log everytime you execute the script. If you want the output to be appended, instead of overwriting the file, add this at the top of your script instead.

exec &>>/tmp/log

Algorithm and Sample C Code to Check if a Number is a Palindrome – Without Reversing the Digits

A friend posted this question on my college mailing list.

How do we find if a Number is a Palindrome?

Note: No conversion to string. And also, no traditional method of dividing the number to construct the reversed number and then compare.

Here is how you go about it.

  1. Lets say the number is 1987891 (odd number of digits)
  2. Reduce it to 198891. If the number were 19877891 (even number of digits) don’t change it (basically change it to a number with even number of digits, by excluding the middle digit)
  3. Now Split it into 198 and 891
  4. If ((891-198)%9 == 0 and (891*1000+198)%11 == 0 and (198*1000+891)%11 == 0) then its a palindrome

Sample C Code

#include <stdio.h>

int numdigits(int n) {
    int count = 0;
    while(n != 0)   {
        n /= 10;
        ++count;
    }
    return count;
}

int main(void) {
    int n;
    int l;
    int a,x;
    int n1, n2, n3;
    scanf("%d",&n);
    l=numdigits(n);     /* Find the number of digits */
    a=1;
    for(x=0;x<l/2;x++)
        a*=10;
    n1=n%a;
    n2=n/a;
    if(l%2)
        n2/=10;
    if (((n1-n2)%9 == 0) && ((n2*a+n1)%11 == 0) && ((n1*a+n2)%11 == 0)) {
        printf("%d\t",n);
        return 0;
    }
    return 1;
}

To compile it

gcc -o palindrome palindrome.c

You can verify that above code works using the below script.

#!/bin/bash

for (( i = 0; i < 100000; i++ )); do
  echo $i | ./palindrome
done

The script assumes that the palindrome binary is in the present working directory.

Jotted this down for school students scouring the web for their homework answers: 😉

Add Copy-Paste Functionality to Xterm, Rxvt like Terminals

Xterm, Rxvt like terminals do not support the traditional Ctrl C Ctrl V kind of copy paste functionality. Does anybody need it? Well I guess not, because you can highlight text, and then use the middle-click to paste it wherever you want. However if anybody needs it, this is what you need to do. Go ahead and install the ttyecho tool from this post of mine. Continue reading

Ruby On Rails: Use Rails.env instead of RAILS_ENV for Rake Custom Tasks for Rails 3

RAILS_ENV returns an empty value in custom rake tasks rails 3.0.0.rc onwards. Instead use Rails.env.

Example Usage:

Lets say you want to determine if you are running the development environment then you could use the following method.

desc "Raise an error unless the RAILS_ENV is development"
task :development_environment_only do
  raise "Hey, development only you monkey!" unless RAILS_ENV == 'development'
end

Now to ensure your custom method is running in development environment, call the development_environment_only method as a dependency of your rake custom task.

task :abc => [:environment, :development_environment_only] do
end

If you wish to pass arguments to your rake task, then the code to call the dependencies would be:

task :abc, :argument, :needs => [:environment, :development_environment_only] do |t, args|
end

Ruby On Rails: Validate atleast one Checkbox is Checked in a Form

Lets say you have a form with the following checkboxes.

<%= f.check_box :checkbox1 %>
<%= f.check_box :checkbox2 %>
<%= f.check_box :checkbox3 %>

Now to make sure atleast one checkbox is checked, add the following code to your model.

  validate :atleast_one_is_checked

  def atleast_one_is_checked
    errors.add(:base, "Select atleast one output format type") unless checkbox1 || checkbox2 || checkbox3
  end

Bash Tricks: Split / Cut a String with Multi Character Delimiters

Its simple enough to split a string when it has single character delimiters using the cut command. However cut doesn’t support multi-character delimiters. Here’s a sample script to demonstrate how to split strings with multi-character delimiters.

#!/bin/bash
#Inputs to the script, the delimiter, and the string itself
D="<>"   #Multi Character Delimiter
string="abcd<>efgh<>ijkl<>mn op<>qr st<>uv wx<>yz" #String with delimiters

#Split the String into Substrings
sList=($(echo $string | sed -e 's/'"$D"'/\n/g' | while read line; do echo $line | sed 's/[\t ]/'"$D"'/g'; done))
for (( i = 0; i < ${#sList[@]}; i++ )); do
  sList[i]=$(echo ${sList[i]} | sed 's/'"$D"'/ /')
done

#Output the Split String
echo No of SubStrings - ${#sList[@]}
for (( i = 0; i < ${#sList[@]}; i++ )); do
  echo ${sList[i]}
done


In the above script, the string is being split and then stored in the sList array. You can access the individual substrings using ${sList[0]}, ${sList[1]}, ${sList[2]} etc. The output for the above script is:

@$ sh cut.sh 
No of SubStrings - 7
abcd
efgh
ijkl
mn op
qr st
uv wx
yz

For those who are wondering how to cut using the cut command. Here’s an example

echo "a|b|c|d|e" |  cut -d '|' -f 1
echo "a|b|c|d|e" |  cut -d '|' -f 2
echo "a|b|c|d|e" |  cut -d '|' -f 3
etc..

Bash Tricks: Create variables dynamically using some eval magic

There are times when you are writing a script and you have the name of a variable as a variable and the desired value as another variable. Now you want to declare the stored name as a variable and assign the stored value to it. This is how you do it.

#!/bin/bash

variableName="test"
variableVal="123"
eval ${variableName}=`echo -ne \""${variableVal}"\"`

echo $test #"test" variable created dynamically using eval

What the script does is, it creates a variable with a name same as the string(“test”) stored in $variableName, and assigns it the value equal to the one stored in $variableVal(“123”).