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.

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[@]}
  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"

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/ ‘&’

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

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.

#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"'/ /')

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

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 
No of SubStrings - 7
mn op
qr st
uv wx

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

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.


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”).

Find the Absolute Path / Directory of a Bash Script

Recently, while writing a script I needed to know what directory the script resides in from within the script. A few google searches later I found a couple solutions. Jotting them down here for fellow googlers. 🙂

Solution 1:

ABSPATH="$(cd "${0%/*}" 2>/dev/null; echo "$PWD"/"${0##*/}")"
DIRPATH=`dirname "$ABSPATH"`

Solution 2:

LSOF=$(lsof -p $$ | grep -E "/"$(basename $0)"$")
ABSPATH=$(echo $LSOF | sed -r s/'^([^\/]+)\/'/'\/'/1 2>/dev/null)

I ended up using Solution 1, because its not dependent on any external command.