Pages

Generate Morse Code from ASCII

The Morse code, named after its inventor Samuel Morse, was used for long distance communication.
It is largely believed that it is now obsolete, yet some prisoners still find it useful. (banging a shoe on a pipe)
Learn more about it at Wikipedia.

Anyway here is the script
#!/bin/bash
# morse.sh - generate morse code from ascii
# you can contact me at:
# --. .-. ..- .-.. --- ... .--.-. --. -- .- .. .-.. 
# .-.-.- -.-. --- --

HTTP authentication, base64 encoding

In the previous post dyndee.sh - dyndns update client, I faced a problem: I had to authenticate to dyndns.org but didn't want to use lynx, links or any other external tool.
For HTTP authentication to work I need to base64 encode the string "username:password"
I will try to explain each step.

dyndee.sh - dyndns update client

Just a minimalistic dyndns.org update client written entirely in bash.
The only requirement is that bash should be compiled with --enable-net-redirections which on many systems is by default.

It gets the ip from http://metawire.org/~inode/ip.php which is a simple
<?php echo $_SERVER['REMOTE_ADDR']; ?>

It can be modified to use others such as checkip.dyndns.org
If you find any bug or have any requests, contact me.
#!/bin/bash
# dyndee.sh - update client for dyndns.org
# written entirely in bash

substrings, brace expansion, sequence expressions

Let's say you have a set of files in a directory named like
exp1eve1.txt
exp1eve2.txt
exp1eve3.txt
exp1eve4.txt
and you want to change the exp1 part to exp2 so they become
exp2eve1.txt
exp2eve2.txt
...

BASH_REMATCH, regular expressions

Since version 3, bash has an additional binary operator `=~' which is able to handle regular expressions. Every substring which is matched by the subexpression which is in parenthesis can be accessed from the BASH_REMATCH variable.

Here is a small script i use to get the latest freshmeat releases
#!/bin/bash

rarcrack.sh: crack those rar files

There are times when you just "forget" that rar password
first get unrar from http://www.rarlab.com/rar/unrarsrc-3.3.4.tar.gz
and the script
just change wordlist and unrar paths and run it
./rarcrack file.rar

#!/bin/bash
wordfile=/usr/share/dict/words
xrar=/usr/bin/unrar
[ -x "$xrar" ] || exit 1
[ -r "$wordfile" ] || exit 1
[ -r "$1" ] || exit 1
trap 'printf "\n%s\n" "caught signal" && exit 1' 2
try=('|' '/' '-' '\')
i=1
while read line; do
printf "\r%-$((${#pline}+10))s\r%s" "${try[$((i%4))]} trying $line"
"$xrar" e -p"$line" "$1">/dev/null 2>&1 &&
printf "\r%-$((${#line}+10))s\n" "password: $line" && exit 0
((i++))
pline=$line
done<$wordfile
printf "%s\n" "tried $i passwords but no luck!"

shell tip: dealing with weird filenames

I know its frustrating. Thank god there is the end of options list.


-bash-3.00$ cd -=test=- # nope
-bash: cd: -=: invalid option
cd: usage: cd [-L|-P] [dir]
-bash-3.00$ cd "-=test=-" # nope
-bash: cd: -=: invalid option
cd: usage: cd [-L|-P] [dir]
-bash-3.00$ cd '-=test=-' # nope
-bash: cd: -=: invalid option
cd: usage: cd [-L|-P] [dir]
-bash-3.00$ cd \-\=test\=\- # nope
-bash: cd: -=: invalid option
cd: usage: cd [-L|-P] [dir]
-bash-3.00$ cd -- -=test=- # yes
-bash-3.00$ cd ..
-bash-3.00$ rmdir -- -=test=- # yes
-bash-3.00$

script: massping.sh: mass ping scanner

pretty fast
i know.. some ranges are not valid. More checking needs to be done

#!/bin/bash
#
# ./shping.sh 192.168.0.1-150

function usage() {
echo "usage example: $0 192.168.0.1-100"
exit 1
}

IFS='.'
iprange=($@) # 192 168 0 1-100
IFS=$'\040\t\n' # printf "$IFS"|hexdump -bc
srange=${iprange[3]/%-*/} # 1
erange=${iprange[3]/#*-/} # 100
j=0

# Do some checking
[ "$#" == "1" ] && # only 1 arg
[ ${iprange[*]//[[:digit:]]/} ] && # does it exist?
[ ${#iprange[@]} == 4 ] && # x.x.x.x
[ ${iprange[*]//[[:digit:]]/} == "-" ] ||
usage


# values within 0.0.0.0-255.255.255.255
for i in "${iprange[@]:0:3}" "$srange" "$erange"; do
[ $i ] &&
[ $i -le 255 ] &&
[ $i -ge 0 ] ||
usage
done

# change 192.168.0.10-1 to 192.168.0.1-10
if [ $srange -gt $erange ]; then
trange=$srange
srange=$erange
erange=$trange
fi

# add dots & feed the array
for ((i=$srange; $erange >= i; i++)) do
iplist[$j]="${iprange[@]:0:3}.$i"
iplist=("${iplist[@]// /.}")
(( j++ ))
done

# now feed ping with random ips
for i in ${iplist[@]}; do
r=$(( RANDOM%${#iplist[@]} ))
ping -c1 -s0 ${iplist[$r]}>/dev/null && echo ${iplist[$r]} &
iplist[$r]=""
iplist=(${iplist[@]})
done

exit 0;

script: expect.sh: using bash instead of expect

because i hate expect scripting
try this:

#!/bin/bash
expect=("hi" "white" "in")
reply=("hello" "black" "out")

while read -n1 "char"; do
word="$word$char"
[ "$word" == "${expect[$count]:0:${#word}}" ] || word="$char"
if [ "$word" == "${expect[$count]}" ]; then
printf "\n${reply[$count]}\n"
(( count++ ))
[ "$count" == "${#expect[@]}" ] && break
word=""
fi
done

script: uptime.sh: get uptime from /proc/uptime

Just a simple script to get uptime from /proc/uptime (which is in seconds)

#!/bin/bash
# uptime.sh
# get uptime from /proc/uptime

uptime=$(</proc/uptime)
uptime=${uptime%%.*}

seconds=$(( uptime%60 ))
minutes=$(( uptime/60%60 ))
hours=$(( uptime/60/60%24 ))
days=$(( uptime/60/60/24 ))

echo "$days days, $hours hours, $minutes minutes, $seconds seconds"

Ofcourse in the same way you could add months, years, decades etc.
you got the idea.

script: renumdir.sh: rename dirs to sequentially numbered ones


#!/bin/bash
#
# renumdir.sh: renames dirs to sequentially
# numbered ones starting from 00001
# ex. 00001 00002 00003 00004 etc.
#
# questions? suggestions? comments?
# grulosΨgmail.com
#

cd $1 || exit 1
typeset -a files=(*)
typeset -i j=1

for i in "${files[@]}"; do

if [ -d "$i" ]; then
# infinite loop until we find the next
# numbered dir we are going to use

while true; do
fname=0000$j;

# we want only 5 digits
# why didn't i just use printf "%05d" ? :P
fname=${fname:$(( ${#fname}-5 ))};

# check if the dir is already numbered
# in that case move to next dir
[ "$fname" == "$i" ] && j=$(( j+1 )) && break

if [ -d "$fname" ]; then
j=$(( j+1 ));
continue;
else
mv -- "$i" "$fname"
j=1
break
fi
done
fi
done

Now just choose the directory holding all the dirs you want to rename and just run it

~$ cd testdir/
~/testdir$ mkdir a b c d e f g h i 1 2 3
~/testdir$ cd ..
~$ ./renumdir.sh testdir/
~$ ls testdir/
00001/ 00002/ 00003/ 00004/ 00005/ 00006/ 00007/ 00008/ 00009/ 00010/ 00011/ 00012/

shell tip: echo * and printf

~$ mkdir testdir
~$ cd testdir
~/testdir$ touch -- -e \\141
~/testdir$ ls
-e \\141
~/testdir$ echo *
a
~/testdir$
note i used '--' with touch so '-e' would not be used as an option.
So what happened here?
-e was passed to echo as an option.
echo *
becomes
echo '-e' '\141'
which interpreted correctly the \141 escape sequence as 'a'
If you're going to use * be careful. Avoid echo try printf.
In this case:
~/testdir$ printf "%s\n" *
-e
\141
~/testdir$

shell tip: get parts of a filename

# works in bash, zsh and ksh93
~$ f=file.tar.bz2
~$ echo "${f##*.}"
bz2
~$ echo "${f#*.}"
tar.bz2
~$ echo "${f%.*}"
file.tar
~$ echo "${f%%.*}"
file

shell tip: var of var

~$ a=1
~$ b=a
~$ echo $((b))
1

Why save $IFS to OIFS ?

A lot of people seem to get confused just because $IFS contains non printing characters. Many suggest that before changing IFS (while using a modern shell) it should be saved in a variable such as OIFS. Others suggest going into a subshell so the original IFS won'be changed. Looking at IFS as it is by default on my system it's just space tab and newline

~$ echo -En "$IFS"|hexdump -bc
0000000 040 011 012
0000000 \t \n
0000003

So if you know what IFS you need just set it to that. In bash, zsh, ksh93 the following works fine. IFS=$'\040\t\n' Do any IFS changing you want and then set it to that.

~$ string=a/b/c
~$ IFS='/'
~$ set -- $string
~$ IFS=$'\040\t\n'
~$ echo $1,$2,$3
a,b,c