1. 结构化命令
(1)if-then语句
if command
then
commands
fi
示例:
#!/bin/bash
#testing multiple commands in the then section
testuser=root
if grep $testuser /etc/passwd
then
echo the bash files for user $testuser are:
ls -a /root/.b*
fi
grep是一个文本匹配命令。
(2)嵌套if语句
if command1
then
commands
elif command2
then
more commands
fi
示例:
#!/bin/bash
#testing the else section
testuser=badtest
if grep $testuser /etc/passwd
then
echo the files for user $testuser are:
ls -a /home/$testuser/.b*
else
echo "the user name $testuser doesn't exist on the system"
fi
(3)test命令
有两种形式:
if test condition
then
commands
fi
与:
if [ condition ]
then
commands
fi
test命令主要是提供一种检测if-then语句中不同条件的方法。如果test评估条件为true,那么test命令以状态码0退出。
数值比较:
n1 -eq n2 检查n1是否等于n2
n1 -ge n2 检查n1是否大于等于n2
n1 -gt n2 检查n1是否大于n2
n1 -le n2 检查n1是否小于等于n2
n1 -lt n2 检查n1是否小于n2
n1 -ne n2 检查n1是否等于n2
示例:
#!/bin/bash
#using numeric test comparsions
var11=10
var12=11
if [ $var11 -gt 5 ]
then
echo "the test value $var11 is greater than 5"
fi
if [ $var11 -eq $var12 ]
then
echo "the values are equal"
else
echo "the values are different"
fi
字符串比较:
str1=str2 检查str1与str2是否相同
str1!=str2 检查str1与str2是否不同
str1<str2 检查str1是否小于str2
str1>str2 检查str1是否大于str2
-n str1 检查str1的长度是否大于0
-z str1 检查str1的长度是否为0
当比较一个字符串是大还是小时,一定要用转义字符进行转义,要不就当成重定向了。
示例:
#!/bin/bash
#>号会理解成重定向,因此需要转义
var11=aeball
var12=hockey
if [ $var11/>$var12 ]
then
echo "$var11 is greater than $var12"
else
echo "$var11 is less than $var12"
fi
#!/bin/bash
va11=testing
va12=''
if [ -n $vall ]
then
echo "the string '$va11' is not empty"
else
echo "the string '$va11' is empty"
fi
if [ -z $va12 ]
then
echo "the string '$va12' is empty"
else
echo "the string '$va12'is not empty"
fi
if [ -z $va13 ]
then
echo "the string '$va13' is empty"
else
echo "the string $va13 is not empty"
fi
~
文件比较:
-d file 检查file是否存在并且是一个目录
-e file 检查file是否存在
-f file 检查file是否存在并且是一个文件
-r file 检查file是否存在并且可读
-s file 检查file是否存在并且不为空
-w file 检查file是否存在并且可写
-x file 检查file是否存在并且可执行
-O file 检查file是否存在并且被当前用户拥有
-G file 检查file是否存在并且默认组是否为当前用户组
file1 -nt file2 检查file1是否比file2新
file1 -ot file2 检查file1是否比file2旧
示例:
检查目录:
#!/bin/bash
#look before you leap
if [ -d $HOME ]
then
echo "your home directory exists"
cd $HOME
ls -a
else
echo "there's a problem with your HOME directory"
fi
检查对象是否存在:
#!/bin/bash
#checking if a directory exists
if [ -e $HOME ]
then
echo "OK on the directory,now let's check the file"
if [ -e $HOME/testing ]
then
echo "Appending data to existing file"
date>>$HOME/testing
else
echo "creating new file"
date >$HOME/testing
fi
else
echo "sorry,you don't have a home directory"
fi
检查文件:
#!/bin/bash
#check if a file
if [ -e $HOME ]
then
echo "the object exists,is it a file?"
if [ -f $HOME ]
then
echo "yes it's a file"
else
echo "no it's not a file"
if [ -f $HOME/.bash_profile ]
then
echo "but this is a file"
fi
fi
else
echo "sorry the object doesn't exist"
fi
检查是否可读:
#!/bin/bash
#testing if you can read a file
pwfile=/etc/shadow
if [ -f $pwfile ]
then
if [ -r $pwfile ]
then
tail $pwfile
else
echo "sorry,the ‘'$pwfile' can't read"
fi
else
echo "sorry,the $file doesn't exist"
fi
检查文件是否为空:
#!/bin/bash
#testing if a file is empty
file=test15
if [ -s $file ]
then
echo "the $file exists and has data in it"
var=`date'
else
echo "the $file exists and is empty"
fi
检查文件是否可写:
#!/bin/bash
#checking if a file is writeable
logfile=/home/t16test
touch $logfile
chmod u-w $logfile
now=`date +%y%m%d-%H%M`
if [ -w $logfile ]
then
echo "the program ran at: $now">$logfile
echo "the first attempt succeeded"
else
echo "the first attempt failed"
fi
chmod u+w $logfile
if [ -w $logfile ]
then
echo "the program ran at: $now">$logfile
echo "the second attempt succeeded"
else
echo "the second attempt failed"
fi
检查文件是否可执行:
#!/bin/bash
#testing file execution
if [ -x test16 ]
then
echo "you can run the script"
./test16
else
echo "sorry,you can't execute the script"
fi
(4)复合条件查询
if-then语句可以使用复合条件查询。
if [ condition1 ] && [ condition2 ]
[ condition1 ] || [condition2 ]
示例:
#!/bin/bash
#testing compound comparsions
if [ -d $HOME ] && [ -w $/HOME/testing ]
then
echo "the file exists and you can write to it"
else
echo "I can't write to the file"
fi
(5) if-then的高级特征
双圆括号表示数学表达式。
双方括号表示高级串处理函数
(( expression ))
expression可以是:
val++ 后增量
val-- 后减量
++val 前增量
--val 前减量
! 逻辑否定
~ 按位取反
** 取幂
<< 按位左移
>> 按位右移
[[ expression ]]
expression主要是与使用的标准字符串比较,提供了模式匹配的功能。
示例:
圆括号:
#!/bin/bash
#using double parenthesis
var1=10
if (( $var1**2>90 ))
then
((var2=$var1**2))
echo "the square of $var1 is $var2"
fi
方括号:
#!/bin/bash
#using pattern matching
if [[ $USER==r* ]]
then
echo "hello $USER"
else
echo "sorry,i don't know you"
fi
(6) case 命令
case命令格式:
case variable in
pattern1|pattern2) commands1;;
pattern3)commands2;;
*)default commands;;
esac
示例:
#!/bin/bash
#using the case command
case $USER in
rich|root)
echo "welcome,$USER"
echo "please enjoy your visit";;
testing)
echo "special testing account";;
jessica)
echo "don't forget to log off when you're done";;
*)
echo "sorry,you're not allowed here";;
esac
(7) for命令
格式:
for var in list
do
commands
done
读取列表的值,然后进行迭代。
a.读取列表中的简单值:
#!/bin/bash
#basic for command
for test in Alabama Alaska Arizona Arkansas California Colorado
do
echo the nest state is $test
done
b.读取列表中的复杂值:
#!/bin/bash
#another example of how not to user the for command
#当遇到单引号时,需要用双引号,或者用/转 义
for test in I don/'t know if "this'll" work
do
echo "word:$test"
done
分析:在上面的脚本中遇到了单引号,don't与this'll必须进行转义或者是用双引号。
#!/bin/bash
#for 命令是用空格来分隔列表中的值,然后当个别数值中有空格时,应当用双引号包围
for test in Nevadaw "New York" "New Mexico"
do
echo "Now going to $test"
done
分析:for命令默认是用空格来分割,如果个别值中有空格时,应当用双引号包围起来。
c.读取命令中的值:
#!/bin/bash
#reading values from a file
file="states"
for state in `cat $file`
do
echo "visit beautiful $state"
done
分析: cat $file用的是反引号。
d.改变字段分割符:
默认情况下,shell将空格,制表符,换行符看成是字段分割符。
如果把字段分割符IFS更改为换行符,则IFS=$'/n'
#!/bin/bash
#改变字段分隔符,bash shell的字符分隔符有以下几种: 空格,制表符,换行符
file="states"
IFS=$'/n'
for state in `cat $file`
do
echo "visit beautiful $state"
done
IFS=$IFS.OLD #还原内部字段分隔符
e.使用通配符读取目录:
#!/bin/bash
#interate through all the files in a directory
for file in /home/*
do
if [ -d "$file" ]
then
echo $file is a dir
elif [ -f "$file" ]
then
echo "$file is a file"
fi
done
(8)C 式for命令
格式:
for (( a=1;a<10;a++ ))
单个变量:
#!/bin/bash
#testing the C-style for loop
for ((i=1;i<=10;i++))
do
echo "the next number is $i"
done
多个变量:
#!/bin/bash
#multiple variables
for ((a=1,b=10;a<=10;a++,b--))
do
echo "$a-$b"
done
(9) while命令
格式:
while test command
do
other commands
done
#!/bin/bash
#while command test
var1=10
while [ $var1 -gt 0 ]
do
echo $var1
var1=$[ $var1-1 ]
done
#!/bin/bash
#testing a multicommand while loop
var1=10
while echo $var1
[ $var1 -ge 0 ]
do
echo "this is inside the loop"
var1=$[ $var1-1 ]
done
分析:两条测试命令,一条是 echo $var1,另一条是 [ $var1 -ge 0 ]
2. 命令行参数
(1)读取参数
向shell脚本传递数据最基本的使用命令行参数(command line parameters).
$0 表示程序名称 $1表示第一个参数 $2表示第二个参数 ..... $9表示第9个参数
如果使用第10个参数就用 ${10}
#!/bin/bash
#using one command line parameter
factorial=1
for ((number=1;number<=$1;number++))
do
factorial=$[ $factorial*$number ]
done
echo the factorial of $1 is $factorial
./test1 5
(2)读取程序名称
basename只返回程序名称,不带路径。
#!/bin/bash
#testing a multi-function script
name=`basename $0`
if [ $name="addem" ]
then
total=$[ $1+$2 ]
elif [ $name="multem" ]
then
total=$[ $1*$2 ]
fi
echo the caculated value is $total
(3) 参数计数
$#存储的是包含命令行参数的个数。
#!/bin/bash
if [ $# -ne 2 ]
then
echo Usage:test9 a b
else
total=$[ $1+$2 ]
echo the total is $total
fi
#!/bin/bash
#grabbing the last parameter
params=$#
echo the last param is $params
echo the last parameter is ${!#}
${!#}得到最后个命令行参数的值。
当没有任何参数时,即$#等于0,那么${!#}将返回脚本的名称。
(4)获取所有数据
$* 把命令行提供的所有参数当成一个单词处理。
$@ 把命令行提供的所有参数当成同一个字符串中的多个单词进行处理。
#!/bin/bash
#获得所有数据
#testing s* and S@
count=1
for param in "$*"
do
echo "/S* parameter #$count=$param"
count=$[ $count+1 ]
done
count=1
for param in "$@"
do
echo "/$@ parameter #$count=$param"
count=$[ $count+1 ]
done
结果:
[root@localhost chapter11]# ./test11 a b c d e
/S* parameter #1=a b c d e
$@ parameter #1=a
$@ parameter #2=b
$@ parameter #3=c
$@ parameter #4=d
$@ parameter #5=e
3. 获取用户输入
read命令接收标准的键盘读入.
(1)基本读取
#!/bin/bash
#testing the read -p option
read -p "please enter your age:" age
days=$[ $age*365 ]
echo "that makes you over $days days old!"
read -p允许在命令行中直接指定一个提示。
[root@localhost chapter11]# ./test22
please enter your age:10
that makes you over 3650 days old!
如果不指定变量,那么read命令将数据接收到环境变量REPLY中去。
#!/bin/bash
#testing the REPLY environment variable
read -p "Enter a number:"
factorial=1
for ((count=1;count<=$REPLY;count++))
do
factorial=$[ $factorial*$count ]
done
echo "the factorial of $REPLY is $factorial"
(2)计时
read命令,脚本会停止下来等待输入,可以指定一定的时间,当超过这个时间后,继续执行后面的脚本。
read -t
#!/bin/bash
#timing the data entry
if read -t 5 -p "please enter your name:" name
then
echo "hello $name,welcome to my script"
else
echo
echo "sorry ,two slow"
fi
~
分析:当超过5秒不输入时,自动执行后面的脚本。
read -n1 表示接收到1个字符就退出。
#!/bin/bash
#getting just one character of input
read -n1 -p "Do you want to continue[Y/N]?" answer
case $answer in
Y|y)echo
echo "fine,continue on....";;
N|n)echo
echo Ok,goodbye
exit;;
esac
echo "this is the end of the script"
(3)默读
当用户的输入不显示在显示器上,即把文本颜色设置成背景颜色即可。 read -s
#!/bin/bash
#hiding input data from the monitor
read -s -p "Enter your password:" pass
echo
echo "Is your password really $pass?"
(4)读取文件
即从文件中读取数据,
#!/bin/bash
#reading data from a file
#通过管道将数据送给read命令
count=1
cat /etc/passwd|while read line
do
echo "Line $count:$line"
count=$[ $count+1 ]
done
总结:这篇文章主要shell脚本的一些基本结构化命令,如if,for,while.以及命令行参数,$1,$2,$#,$*,$@.最后还有读取用户输入命令read.
接下来的文章主要介绍shell高级编程部分,包括正则表达式,sed,gawk.