life ideas

September 12, 2006

bash script from hands-on experience

Filed under: script, Uncategorized — manoftoday @ 5:22 pm
  • there are two formats in command substitution:
content="$(cat ./mylog)"
web_files=`ls ./public_html`


  • Using Quotes to enclose your variables <—–important

X=""
if [ -n "$X" ]; then 	# -n tests to see if the argument is non empty
	echo "the variable X is not the empty string"
fi

  • Using Braces to Protect Your Variables

    OK. Here’s a potential problem situation. Suppose you want to echo the value of the variable X, followed immediately by the letters “abc”. Question: how do you do this ? Let’s have a try :

    #!/bin/bash
    X=ABC
    echo "$Xabc"

    THis gives no output. What went wrong ? The answer is that the shell thought that we were asking for the variable Xabc, which is uninitialised. The way to deal with this is to put braces around X to seperate it from the other characters. The following gives the desired result:

    #!/bin/bash
    X=ABC
    echo "${X}abc"
  • test conditions

The test command needs to be in the form “operand1<space>operator<space>operand2” or operator<space>operand2

for string : -n, =, !=

for integer : lt, gt,eq,neq,ge,le

file: -f , -d

if [ ! -f “./myfile” ]; then

else

fi

  • bash parses commands by space

bash gets unhappy if you leave a space on either side of the = sign. For example, the following gives an error message:

X = hello

the correct one should be X=”hello”

  • send e-mail
approach 1:
EMAIL_BODY=/location/of/original    #this file contains your body(template)

# these following sed commands make a new email to be sent with the user input substituted

# this first sed command creates a new email body that will be sent with the mail command
# since the -i option is not used a new email will be made, without changeing your original
sed "s/PassWord/$PASSWORD/" ${EMAIL_BODY} > ammended_email

# the -i option is used now because it will be changeing the new ammended email
sed -i "s/EmAil/$EMAIL/" ammended_email
sed -i "s/UsEr/$USER_NAME/" ammended_email

mail -s "subject" person@gmail.com < ammended_email
approach 2:
mail -s "subject" person@gmail.com <<EOF
hello,this is $USER
EOF

  • read from file
1) a singleline process
#rename from *.txt -> *.text’
find /tmp -name '*.txt' |while read line; do newname=$(echo ${line}|sed 's/txt$/text/'); mv -v "${line}" "${newname}"; done

2) while loop
while read curline; do
         echo  $curline
done < "/tmp/yourfile"
#!/bin/sh
while read inputline
do
   login="$(echo $inputline | cut -d: -f1)"
   fulln="$(echo $inputline | cut -d: -f4)"
   echo login = $login and fullname = $fulln
done < /etc/passwd

3) read the whole file
  	content = "$(cat /tmp/yourfile)"
  • wait a job to be finished
>I'm looking for a way to allow a process to run for a maximum of x milliseconds. I've made a clumsy script
> using "sleep", but it has the disadvantage that each
> run takes exactly x milliseconds. I would prefer to
> allow the process to finish sooner.
>
> This was my idea:
>
> for file in *.bf
> do
>  cat $file | bf > ${file%.bf} &
>  sleep 0.5
>  killall bf
> done

> Comments?

You probably want to be doing something with "$!", the PID of the last spawned
background job.

For example:

# Start some time consuming job in background...
sh -c "sleep 5" &
JOB=$!

# Start its nemesis
sh -c "sleep 1 ; kill $JOB" &

# Wait for the job to finish, but don't wait for it's killer
wait $JOB

# Carry on/loop to next file or whatever
....

If the first job finishes early the killer should later just emit a
harmless "no such process" error message (unless your sleep time is
so big your system manages to wrap-round the PID range of course :^).
  • how to run in a spawned shell? <—–advanced

test1.sh

#!/bin/bash

export TMPFILE=”/tmp/test.$$.`whoami`”

export LOGFILE=”/tmp/mylog”

MYTRACE=”/tmp/mytrace”

source ~/test2.sh <<‘EOF’

echo “tmpfile is $TMPFILE” # the output has value

echo “log is $LOGFILE” # the out put has /tmp/mylog2

echo “trace is $MYTRACE” # the output is empty

test2.sh

#!/bin/bash
export LOGFILE=”/tmp/mylog2″
echo “tmpfile in bash2 is $TMPFILE” # the output has value
echo “log in bash2 is $LOGFILE” # the out put has /tmp/mylog2
echo “trace in bash2 is $MYTRACE” # the out put is empty
/usr/bin/bash –noprofile –norc

in summary,

1)in test1.sh, you need to use export so values can be reserved after EOF; you can’t use variable=value

2) the pid before you run test1.sh and the pid that you echo $$ after test1.sh is finished is the same.

  • Debugging on part(s) of the script

set -x			# activate debugging from here
...
code
...
set +x			# stop debugging from here


  • input arguments

test1.sh

declare flag=””

declare kflag=””
declare rflag=””
declare xflag=””
declare loop_numbers=””

while getopts “:krn:x” flag # -k -r -n 3 -x

do
case $flag in
k) kflag=1;;
r) rflag=1;;
n) loop_numbers=”${OPTARG}”;;
x) xflag=1;;
?) print-usage; exit 2;;
esac
done

enforce parameters

if [ -z $1 ]; then       # no parameter
        echo "Usage: $0 /path/to/httpd.conf"
        exit 1
fi
  • array manipulation
[bob in ~] ARRAY=(one two three)

[bob in ~] echo ${ARRAY[*]}
one two three
[bob in ~] echo ${ARRAY[@]}
 one two three
[bob in ~] echo ${ARRAY[2]}
three

[bob in ~] ARRAY[3]=four

[bob in ~] echo ${ARRAY[*]}
one two three four
[bob in ~] unset ARRAY[1]

[bob in ~] echo ${ARRAY[*]}
one three four

[bob in ~] unset ARRAY

bob in ~] echo ${ARRAY[*]}
<--no output-->

  • arithmetic caculation
#
# Count the number of possible testers.
# (Loop until we find an empty string.)
#
count=0
while [ "x${wholist[count]}" != "x" ]
do
   count=$(( $count + 1 ))
done
  • variables expansion
1)remove parts 



[bob in ~]ARRAY=(one two one three one four)

[bob in ~] echo ${ARRAY[*]}

one two one three one four

[bob in ~] echo ${ARRAY[*]#one}
two three four


[bob in ~] echo ${ARRAY[*]}     # ARRAY itself has no change
one two one three one four

[bob in ~] echo ${ARRAY[*]#t}
one wo one hree one four

[bob in ~] echo ${ARRAY[*]#t*} # one # for shortest match from beginning
one wo one hree one four

[bob in ~] echo ${ARRAY[*]##t*} # two ## for longest match from beginning including spaces

one one one four
similar ,%, and %% match from  the end.
we normally use this for variables, such as :
SZINFO=`echo ${SZINFO##*(}`
         SZINFO=`echo ${SZINFO%%)*}`

2) Replacing parts
 

This is done using the

${VAR/PATTERN/STRING}

or

${VAR//PATTERN/STRING}

syntax. The first form replaces only the first match, the second replaces all matches of PATTERN with STRING:

3) length

[bob in ~] echo $SHELL
/bin/bash

[bob in ~] echo ${#SHELL}
9

[bob in ~] ARRAY=(one two three)

[bob in ~] echo ${#ARRAY}
3

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: