complete reference at http://www.linuxdoc.org/LDP/abs/html

How to trace a bash script

Either launch it with the -v parameter, or include it in the #!/bin/bash line of the script

Dealing with spaces

see this excellent and lively thread.

See also this

But in short...so long as no endlines are in the filename, set IFS to only split on newlines

IFS=$'\n'
for this in $*
   do
   TMP=`mktemp -u XXXXXX`
   TMP=$TMP"_"$this
   mv $this $TMP
   echo $TMP
   done

Simple script to make and edit blank executable file

#!/bin/bash

if [ $# -ne 1 ]
then
   echo "Usage: vix (filename to create)"
   exit 1
fi

if [ -e $1 ]
then
   echo "file $1 already exists"
   exit 1
fi

touch $1

echo "#!/bin/bash" > $1
echo $'\n' >> $1

chmod +x $1
vim $1 +2

Filtering fortunes

#!/bin/bash
MAX_WORDS=100
WORDS=`expr $MAX_WORDS + 1`

while [ $WORDS -gt 100 ]
do
   FORTUNE=`/usr/games/fortune`
   WORDS=`echo $FORTUNE | wc -m`
done

echo $FORTUNE

Temporary files with uninterruptible cleanup

Cool tip from guru Steve Bourne: use the process ID! $$ in the script.

This script which I took from Heiner's SHELLdorado shows how to catch CTRL-C. If you kill the script, we still delete the temporary file.

Note that signal '0' is not really a signal per se, but an internal signal the script sends to itself when it exits. So if signal 15 happens, the exit 2 line occurs, which in turn executes the trap that deletes the temporary file.

#!/bin/bash
# viman - start "vi" with a manual page

Tmp="${TMPDIR:=/tmp}/vm$$"

# Assure the file is removed at program termination
# or after we received a signal:
trap 'rm -f "$Tmp" >/dev/null 2>&1' 0
trap "exit 2" 1 2 3 13 15

EXINIT="set ignorecase nowrapscan readonly"
export EXINIT

man "$@" | col -b | uniq > "$Tmp" || exit

[ -s "$Tmp" ] || exit 0    # file is empty
head -1 < "$Tmp" |
    grep 'No.*entry' && exit 0 # no manual page

${EDITOR:-vi} "$Tmp"

Here's a simpler version: (note, you can do trap -l to see a list of signals)

trap "DONE=1" SIGINT
trap "DONE=1" SIGKILL
DONE=0
while [ $DONE -ne "1" ]
do
   echo "hi"
   sleep 1
done
echo "exited clean!"

test command options

-d file file exists and is a directory
-e file file exists
-r/-w file file exists and is a readable / writeable
-s file file exists and has non-zero size
-x file file exists and is executable
-L file file exists and is a symbolic link
file1 -nt / -ot file2 file1 is newer / older than file2
-n / -z string string has non-zero / zero length
string1 = / = string2 string1 is same / not the same as string2
int1 -eq/-ne/-ge/-le/-gt/lt int2 int1 is equal/not equal/greater than or equal/etc. than int2
! not operator, reverses value of prev condition
-a / -o and/or, joins two conditions
\( ... \) groups conditions

Special shell variables

$# num of args
$0 command name
$1, $2, ..., $9 the args of the command
$* all the args, treated as a single word
$@ all the args, treated as a series of words
$? status of last command (see below, processing exit values)
$$ process id of current process

Handling case statements

to process the first arg of a script...

case $1 in
  -a) echo Got an -a ;;
  -b) echo Got an -b ;;
esac

How to make a list of things

If you do...
mkdir man{1,2,3,4,5,6,7,8}
...it will make 8 man directories, man1, man2, ... man8

How to check if a file/device exists


FILENAME = "/usr/local/junk"

if [ -e "$FILENAME" ]
then
   echo 'exists'
else
   echo 'absent'
fi

How to check count of cmd line args

ARGNO=1         # Number of arguments the script expects.
E_WRONGARGS=65  # It's nice to enumerate the error codes

if [ $# -ne $ARGNO ]
then
  echo "Usage: `basename $0` [arg]" >&2  # Error message >stderr.
  exit $E_WRONGARGS
fi

How to sleep in a script

Easy. To sleep for 2 seconds, do...
sleep 2

How to Process Exit Values from a Program or Script

# run the program
./loadDriver

if [ "$?" -ne "0" ]
then
   echo "failure running program! Exiting."
   exit 1
fi

One liners

Unpacking a bunch of RPMs at once
for this in [ `ls *.rpm` ]; do rpm2cpio $this | cpio -iv --make-directories; done

That cool little example you did for work

cat > /tmp/test << "EOF"; egrep "(([a-z])\2).*\1" /tmp/test; rm /tmp/test; logger "demo run by `whoami` at `date`"; echo "demo run counter at `egrep "demo run by" /var/log/messages | wc --lines | awk '{print $1}'` runs"
mississippi
schoolroom
zookeeper
boring
EOF

The reboot with counter script

#!/bin/bash

COUNT_FILE="/etc/boot/count"

if [ -e $COUNT_FILE ]
then
   BOOTCOUNT=`cat $COUNT_FILE`
else
   BOOTCOUNT=0
fi

COUNT_NOW=`expr $BOOTCOUNT + 1`
logger "boot count @ $COUNT_NOW (`date`)"
echo "$COUNT_NOW" > $COUNT_FILE
# init 6

awk and sort

takes /etc/hosts, prints the 3rd column, then the first column, but sorts according to the second column

less /etc/hosts | awk '{print $3 " " $1}' | sort -k 2

An example with Loops: pounding the drives to reproduce Stretch's issue

Concepts to notice here:
  • Doing arithmetic
  • Loops
  • Using variables as parts of commands

#!/bin/bash

# This script spawns $THREADS instances of dd, doing $WRITES writes
#  of size $DATA_SIZE to dummy files in $JUNK_PATH for purposes of
#  stressing the hard drive

# Where are we going to create the test files?
JUNK_PATH=/mnt/sdb/junk

# Size of each write
DATA_SIZE=16k

# How many writes are we doing per DD?
WRITES=10000

# How many times do we run this crazy test?  We need
#  to do this (vs. just writing more data) b/c otherwise
#  we will run out of disk space
LOOPS_TO_DO=500

while [ $LOOPS_TO_DO -gt "0" ]
do

# How many do we launch at once?
    THREADS=5

# delete the junk we created from last time
    rm "$JUNK_PATH"*
    while [ $THREADS -gt "0" ]
    do

# the last time thru, we want to NOT spawn to the background ('&') so
#  that we wait for the last process to finish before we launch another
#  batch.  This isn't perfect, but it doesn't need to be.  We're trying
#  to thrash things anyway!

        if [ $THREADS -eq "1" ]
        then
            time /bin/dd if=/dev/zero of="$JUNK_PATH$THREADS" bs="$DATA_SIZE" count="$WRITES"
        else
            time /bin/dd if=/dev/zero of="$JUNK_PATH$THREADS" bs="$DATA_SIZE" count="$WRITES" &
        fi
        THREADS=$(($THREADS - 1))
    done
    echo "LOOP! $LOOPS_TO_DO"

    LOOPS_TO_DO=$(($LOOPS_TO_DO - 1))
done

Walking through a list of things, checking for directory existence

Walk through all the .txt. files in BASE_PATH. Then see if a directory exists which has the same name (minus the .txt in PUB_PATH - basename is very handy here). Report if the directory dies not exist.

#!/bin/bash

BASE_PATH=/home/blah
PUB_PATH=/home/blah2

for this in ls $BASE_PATH/*.txt
   do
   THIS_FILE=$PUB_PATH`basename $this .txt`
   if [ ! -d $THIS_FILE ]
   then
      echo "$THIS_FILE dir does not exist"
   fi
   done

Cute File Timestamp Comparison Script

    $ touch old; sleep 1; touch new
    $ test old -nt new && echo true || echo false
    $ test new -nt old && echo true || echo false

Stripping out uninteresting things from a bunch of system event logs

Tried to find a way to overwrite the file so as to not need 2 files, but >! did not work

cp sel sel_strip
sed -n '/OEM System boot event/!p' sel_strip > sel_strip2
sed -n '/Timestamp Clock Sync/!p' sel_strip2 > sel_strip
sed -n '/OEM System boot event/!p' sel_strip > sel_strip2
sed -n '/Timestamp Clock Sync/!p' sel_strip2 > sel_strip
sed -n '/Initiated by hard reset/!p' sel_strip > sel_strip2
sed -n '/Power Button pressed/!p'  sel_strip2 > sel_strip
sed -n '/Initiated by power up/!p' sel_strip > sel_strip2
sed -n '/Power off\/down/!p'  sel_strip2 > sel_strip
sed -n '/Reset Button pressed/!p' sel_strip > sel_strip2
cp sel_strip2 sel_strip
rm sel_strip2
awk -F\| '{print $4 "|" $5}' sel_strip | sort -u > error_types

The STREAM torture tester, problem detector script

#!/bin/bash

DONE=0
#logger -s `cat s[0-9] | awk '{total += $2} END {print total}'`

#logger -s `cat s[0-9] | awk '{total += $2} END {print total}'`
while [ $DONE -eq 0 ]
do
rm -f s[0-9]

  taskset -c 0 ./stream | grep Triad > s1 &
  taskset -c 1 ./stream | grep Triad > s2 &
  taskset -c 2 ./stream | grep Triad > s3 &
  taskset -c 3 ./stream | grep Triad > s4 &
  taskset -c 4 ./stream | grep Triad > s5 &
  taskset -c 5 ./stream | grep Triad > s6 &
  taskset -c 6 ./stream | grep Triad > s7 &
  taskset -c 7 ./stream | grep Triad > s8 &
#  ./stream | grep Triad > s3 &
#  ./stream | grep Triad > s4

while [ `cat s[0-9] | wc -l` -lt 8 ]
do
   echo "z"
   sleep 1
done

RESULT=`cat s[0-9] | awk '{total += $2} END {print total}'`

# throw out decimal part
RESULT=`echo $RESULT | awk -F. '{print $1}'`
echo $RESULT
if [ `expr $RESULT \< 4000` -eq 1 ]
then
   DIR=`mktemp -d ./broke_XXXXX`
   echo $DIR
   cp s[0-9] $DIR
   logger -s "ERROR: $RESULT"
fi
logger -s "OK: $RESULT"
done

-- MattWalsh - 15 Feb 2002

Topic revision: r18 - 25 Dec 2006 - 19:26:00 - MattWalsh
 
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback