Chapter 5 Basic Scripting: Shell Variables

Variables in a bash script are often written as all-uppearcase names,though that is not required——just a common practice.

There are two significant aspects of bash variable syntax:

First, on the assignment, the name=value syntax is straightforward enough, but there cannot be any spaces around the equal sign.

[maxwell@MaxwellDBA test]$ # trival script using shell variables
[maxwell@MaxwellDBA test]$ MYVAR="Hello Kitty"
[maxwell@MaxwellDBA test]$ echo $MYVAR
Hello Kitty
[maxwell@MaxwellDBA test]$ # similar but with no quotes
[maxwell@MaxwellDBA test]$ MY_2ND=anotherone
[maxwell@MaxwellDBA test]$ echo $MY_2ND
anotherone
[maxwell@MaxwellDBA test]$ # quotes are needed here:
[maxwell@MaxwellDBA test]$ MYOTHER="more stuff to echo"
[maxwell@MaxwellDBA test]$ echo $MYOTHER
more stuff to echo
[maxwell@MaxwellDBA test]$ 

The second aspect of shell variable syntax worth noting is the use of the dollar sign when referring to the variable.

The exception to this is using variables inside a $(( ... )) expression.

1.1 Documenting Your Script

Document your script with comments.The # character denotes the begining of a comment.All the characters after # on that line are ignored by the shell.
 

[maxwell@MaxwellDBA test]$ #
[maxwell@MaxwellDBA test]$ # This is a comment
[maxwell@MaxwellDBA test]$ #
[maxwell@MaxwellDBA test]$ # Use comments frequently
[maxwell@MaxwellDBA test]$ # Comments are your friends.
[maxwell@MaxwellDBA test]$ 

Comments can even be typed in at the command prompt with an interactive shell.

1.2 Embedding Documentation in Shell Scripts

Embed documentation in the script using the "do nothing" built in (a colon) and a here-document:

[maxwell@MaxwellDBA test]$ cat embedded_documentation
#!/usr/bin/env bash
#cookbook filename: embedded_documentation

echo 'Shell script code goes here'

# Use a : NOOP and here document to embed documentation,
:<<'ÉND_OF_DOCS'

Embedded documentation such as Perl's Plain Old Documentation(POD),or even plain text here.


Any accurate documentaion is better than none at all.

Sample documentation in Perl's Plain Old Documentation(POD) format adapted from CODE/ch07/Ch07.001_Best_Ex7.1 and 7.2 in Perl Best Practices.

=head1 Name

MY~PROGRAM--One line description here

=head1 SYNOPSIS

 MY-PROGRAM [OPTIONS] <file>

=head1 OPTIONS

  -h = This usage.
  -v = Be verbose.
  -V = Show version,copying and license information.

=head1 DESCRIPTION

A full description of the application and its features.
May include numerous subsections(i.e. =head2, =head3,etc.)

[...]

=head1 LICENSE AND COPYRIGHT

=cut

END_OF_DOCS

[maxwell@MaxwellDBA test]$

extract and use that POD documentation, try these commands.

[maxwell@MaxwellDBA test]$ # To read on-screen,automatically paginated
[maxwell@MaxwellDBA test]$ perloc func_choose.sh
-bash: perloc: command not found
[maxwell@MaxwellDBA test]$ # Just the "usage" sections
[maxwell@MaxwellDBA test]$ pod2usage func_choose.sh
[maxwell@MaxwellDBA test]$ 
[maxwell@MaxwellDBA test]$ # Create an HTML version
[maxwell@MaxwellDBA test]$ pod2html func_choose.sh > func_choose.html
-bash: pod2html: command not found
[maxwell@MaxwellDBA test]$ # create a man page
[maxwell@MaxwellDBA test]$ pod2man func_choose.sh > func_choose_man1.sh
pod2man: unable to format func_choose.sh
[maxwell@MaxwellDBA test]$ 

1.3 Promoting Script Readability

  • Documenting Your Script
  • Embedding Documentation in Shell Scripts
  • Indent and use vertical whitespace wisely
  • Use meaningful variable name
  • Break lines as meaningful places at less than 76 characters or so
  • Put the most meaningful bits to the left.
[maxwell@MaxwellDBA test]$ cat readability.sh
#!/bin/bash

# Good
[ $results ] \
  && echo "Got a good result in $results" \
  || echo 'Got an empty result,something is wrong'

# Also good
[ $results ] && echo "Got a good result in $results" \
             || echo 'Got an empty result, something is wrong'

# Ok, but not ideal
[ $results ] && echo "Got a good result in $results" \
  || echo 'Got an empty result, something is wrong'


# Bad
[ $result ] && echo "Got a good result in $results" || echo 'Got an empty result,
something is wrong'

# Bad
[ $results ] && \
  echo "Got a good result in $results" || \
  echo 'Got an empty result, something is wrong'
[maxwell@MaxwellDBA test]$ 

1.4 Separating Variable Names from Surrounding Text

Use the full syntax for a variable reference, which includes not just the dollar sign,but also brace around the variable name:

somescript /tmp/rep${SUM}bay.txt

1.5 Exporting Variables

Export variables that you want to pass on to other scripts.

export MYVAR
export NAME=value
[maxwell@MaxwellDBA test]$ export FNAME=/tmp/scratch
[maxwell@MaxwellDBA test]$ export SIZE=64
[maxwell@MaxwellDBA test]$ export MAX=2048
[maxwell@MaxwellDBA test]$ echo ${FNAME}
/tmp/scratch
[maxwell@MaxwellDBA test]$ echo ${SIZE}
64
[maxwell@MaxwellDBA test]$ echo ${MAX}
2048
[maxwell@MaxwellDBA test]$ 

1.6 Seeing All Variable Values

Use the set command to see the value of all variables and function definitions in the current shell.

Use the env(or export -p) command to see only those variables that have been exported and would be available to a subshell.

[maxwell@MaxwellDBA test]$ set | grep FNAME
FNAME=/tmp/scratch
[maxwell@MaxwellDBA test]$ 

[maxwell@MaxwellDBA test]$ env | grep FNAME
FNAME=/tmp/scratch
[maxwell@MaxwellDBA test]$ export -p | grep FNAME
declare -x FNAME="/tmp/scratch"

1.7 Using Parameters in a Shell Script

Use command-line parameters.Any words put on the command line of a shell script are available to the script as numbered variables:

[maxwell@MaxwellDBA test]$ # simple shell script
[maxwell@MaxwellDBA test]$ echo $1

[maxwell@MaxwellDBA test]$ 

The script will echo the first parameter supplied on the command line when it is invoked.

[maxwell@MaxwellDBA test]$ sh -x simplest.sh you see what I mean
+ echo you
you
[maxwell@MaxwellDBA test]$ sh -x simplest.sh one more time
+ echo one
one
[maxwell@MaxwellDBA test]$ 

You don't need the braces for the single-digit numbers,except to separate the variable name from the surrounding text.Typical script have only a handful of parameter,but when you get ${10} you better use the braces.

[maxwell@MaxwellDBA test]$ cat tricky.sh
echo $1 $10 ${10}
[maxwell@MaxwellDBA test]$ sh -x tricky.sh I II III IV V VI VII VIII IX X XI
+ echo I I0 X
I I0 X
[maxwell@MaxwellDBA test]$

1.8 Looping Over Arguments Passed to a Script

Use the shell special variable $* to refer to all of your arguments, and use that in a for loop like this :

[maxwell@MaxwellDBA test]$ cat chmod_all.sh
#!/usr/bin/env bash
#cookbook filename:chmod_all.sh
#
# change permission on a bunch of files.
#
for FN in $*
do 
    echo changing $FN
    chmod 0750 $FN
done
[maxwell@MaxwellDBA test]$ 
[maxwell@MaxwellDBA test]$ sh -x chmod_all.sh *.txt
+ for FN in $*
+ echo changing asdfwednnrw2rs2esff.txt
changing asdfwednnrw2rs2esff.txt
+ chmod 0750 asdfwednnrw2rs2esff.txt
+ for FN in $*
+ echo changing cong.txt
changing cong.txt
+ chmod 0750 cong.txt
+ for FN in $*
+ echo changing file.txt
changing file.txt
+ chmod 0750 file.txt
+ for FN in $*
+ echo changing more.txt
changing more.txt
+ chmod 0750 more.txt
[maxwell@MaxwellDBA test]$ ls -ltr *.txt
-rwxr-x--- 1 maxwell maxwell 19 Jul 21 15:40 cong.txt
-rwxr-x--- 1 maxwell maxwell 20 Jul 21 15:40 file.txt
-rwxr-x--- 1 maxwell maxwell 21 Jul 21 15:41 more.txt
-rwxr-x--- 1 maxwell maxwell 49 Jul 21 20:43 asdfwednnrw2rs2esff.txt
[maxwell@MaxwellDBA test]$ 

1.9 Handling Parameter with Blanks

[maxwell@MaxwellDBA test]$ cat simpls.sh
#!/bin/bash
#
# simple shell script
ls -l ${1}
[maxwell@MaxwellDBA test]$ sh -x simpls.sh Oh the Waste
+ ls -l Oh
ls: cannot access 'Oh': No such file or directory
[maxwell@MaxwellDBA test]$ sh -x simpls.sh "Oh the Waste"
+ ls -l Oh the Waste
ls: cannot access 'Oh': No such file or directory
ls: cannot access 'the': No such file or directory
ls: cannot access 'Waste': No such file or directory
[maxwell@MaxwellDBA test]$

[maxwell@MaxwellDBA test]$ cat quoted.sh
#note the quotes
ls -l "${1}"
[maxwell@MaxwellDBA test]$ sh -x quoted.sh  "Oh the Waste"
+ ls -l 'Oh the Waste'
-rw-rw-r-- 1 maxwell maxwell 0

1.10 Handling Lists of Parameters with Blanks

It has to do with the $* in the script, used in the for loop. for this case we need to use a different but related shell variable,$@.when it is quoted,the resulting list has quotes around each argument separately.

[maxwell@MaxwellDBA test]$ cat chmod_all2.sh
#!/usr/bin/env bash
# cookbook filename: chmod_all2.sh
#
# change permissions on a bunch of files
# with better quoting in case of filenames with blanks
#
for FN in "$@"
do
    chmod 0750 "$FN"
done
[maxwell@MaxwellDBA test]$ 

The parameter $* expands to the list of arguments supplied to the shell script.

1.11 Counting Arguments

Use the shell built-in variable ${#}.

[maxwell@MaxwellDBA test]$ sh -x check_arg_count.sh myfile is copied into yourfile
+ ((  5 < 3  ))
+ ((  5 > 3  ))
+ printf %b 'Error. Too many arguments.\n'
Error. Too many arguments.
+ printf %b 'usage: myscript file1 op file2\n'
usage: myscript file1 op file2
+ exit 2
[maxwell@MaxwellDBA test]$ sh -x check_arg_count.sh myfile copy yourfile
+ ((  3 < 3  ))
+ ((  3 > 3  ))
+ printf %b 'Argument count correct. Proceeding...\n'
Argument count correct. Proceeding...
[maxwell@MaxwellDBA test]$ 

1.12 Consuming Arguments

Remember this script:

for FN in "$@"
do
    echo changing $FN
    chmod 0750 "$FN"
done
[maxwell@MaxwellDBA test]$ cat use_up_option.sh
#!/usr/bin/env bash
# cookbook filename: use_up_option.sh
#
# use and consume an option
#
# parse the optional argument
VERBOSE=0;
if [[ $1 = -v ]]
then
    VERBOSE=1;
    shift;
fi
#
# the real work is here
#
for FN in "$@"
do
  if (( VERBOSE == 0 ))
     then
         echo changing $FN
     fi
     chmod 0750 "$FN"
done
[maxwell@MaxwellDBA test]$ 

1.13 Getting Default Values

Use the ${:-} syntax when refering to the parameter, and use it to supply a default value:

FILEDIR=${1:-"/tmp"}

the :- operator ,says that if $1 is not set or is null then it will use what follows./tmp as the value.

1.14 Setting Default Values

Use the assignment operator in the shell variable reference the first time you refer to it to assign a value to the variable if it doesn't already have one, as in:

cd ${HOME:=/tmp}
[maxwell@MaxwellDBA test]$ echo ${HOME:=/tmp}
/home/maxwell
[maxwell@MaxwellDBA test]$ unset HOME     # generally not wise to do
[maxwell@MaxwellDBA test]$ echo ${HOME:=/tmp}
/tmp
[maxwell@MaxwellDBA test]$ echo $HOME
/tmp
[maxwell@MaxwellDBA test]$ cd; pwd
/tmp
[maxwell@MaxwellDBA maxwell]$ export HOME="/home/maxwell"
[maxwell@MaxwellDBA ~]$ echo $HOME
/home/maxwell
[maxwell@MaxwellDBA ~]$ 

1.15 Using null As a Valid Default Value.

The ${:=} operator has two case where the new value will be used:

first, when the value of the shell variable has previously not been set;

and second, where the value has been set but is empty,as in HOME=" " or HOME=$OTHER(where $OTHER had no value)

The shell can distinguish between these two cases, and omitting the colon (:) indicates that you want to make the substitution only if the value is unset. If you write only ${HOME=/tmp} without the colon, the assignment will take place only in the case where the variable is not set (never set or explicitly unset).

[maxwell@MaxwellDBA ~]$ echo ${HOME=/tmp}   # no substitution needed
/home/maxwell
[maxwell@MaxwellDBA ~]$ HOME=""     # generally not wise
[maxwell@MaxwellDBA maxwell]$ echo ${HOME=/tmp} # will not substitute

[maxwell@MaxwellDBA maxwell]$ unset HOME # generally not wise
[maxwell@MaxwellDBA maxwell]$ echo ${HOME=/tmp}     # will substitute
/tmp
[maxwell@MaxwellDBA maxwell]$ echo $HOME
/tmp
[maxwell@MaxwellDBA maxwell]$ export HOME="/home/maxwell"
[maxwell@MaxwellDBA ~]$ echo $HOME
/home/maxwell
[maxwell@MaxwellDBA ~]$ 

1.16 Using More Than Just a Constant String for Default

You can use quite a bit more on the righthand side of these shell variable references.

cd ${BASE:="$(pwd)"}

1.17 Giving an Error Message for Unset Parameters

Use the ${:?} syntax when referring to the parameter.bash will print an error message and then exit if the parameter is unset or null.

[maxwell@MaxwellDBA test]$ sh -x check_unset_parms.sh /tmp /dev/null
+ USAGE='usage: myscript scratchdir sourcefile conversion'
+ FILEDIR=/tmp
+ FILESRC=/dev/null
check_unset_parms.sh: line 7: 3: Error. usage: myscript scratchdir sourcefile conversion
[maxwell@MaxwellDBA test]$ cat check_unset_parms.sh
#!/usr/bin/env bash
#cookbook filename: check_unset_parms
#
USAGE="usage: myscript scratchdir sourcefile conversion"
FILEDIR=${1:?"Error. You must supply a scratch directory."}
FILESRC=${2:?"Error. You must supply a source file."}
CVTTYPE=${3:?"Error. ${USAGE}"}
[maxwell@MaxwellDBA test]$ 

1.18 Changing Pieces of  a String

Use a bash parameter expansion feature that will remove text matches a pattern.

[maxwell@MaxwellDBA test]$ cat suffixer.sh 
#!/usr/bin/env bash
# cookbook filename: suffixer
#
# rename files that end in .bad to be .bash

for FN in *.bad
do
    mv "${FN}" "${FN%bad}bash"
done
[maxwell@MaxwellDBA test]$

1.19 Using Array Variables

. bash now has an array syntax for single-dimension arrays

Arrays are easy to initialize if you know the values as you write the script.

The format is simple:      

MYRA=(first second third home)

[maxwell@MaxwellDBA test]$ MYRA=(first second third home)
[maxwell@MaxwellDBA test]$ echo runner on ${MYRA[0]} and ${MYRA[2]}
runner on first and third
[maxwell@MaxwellDBA test]$ 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值