Pages

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