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