一、什么是Shell
在Linux中,系统会为每个用户运行一个shell(外壳)程序。
shell程序是一个命令行解释器,交互式地解释和执行用户输入的命令。
shell还是一种解释性的程序设计语言,定义了变量和函数,数组,程序控制结构等很多高级语言支持的特性。
二、shell编程用在什么地方
shell一般用于批量命令执行,用来管理,监控系统等。
三、shell语法详解
1.程序示例,输出"hello world"
firstshell
#!/bin/bash echo "hello world"
改变文件的访问权限,使其具有可执行属性
chmod +x firstshell
输出结果:
程序的第一行必须是 #!/bin/bash
指定系统用#!后的命令/bin/bash来运行此文件。
2.变量
varname=值
需要注意的是:
1)"="前后不能有空格
2)变量默认都是字符串格式的
3)使用变量,必须加上"$"符号,否则取到的是变量名本身
4)若变量名和其他字符串混淆在一起时,需要加上{}来区分变量名
如下例所示:
myshell
#!/bin/bash var1=1 var2=2 var3=$var1+$var2 #变量默认是字符串,所以输出为1+2 var4 =4 #等号前后有空格,报错 echo $var1 echo $var2 echo $var3 echo $var4 echo "var1 is the ${var1}st"
输出结果:
那么,我们如何将var1,var2作为数值类型来相加呢?
方法一:使用C风格表示式,((表示式))
((var3=$var1+$var2))
或((var3=var1+var2))
方法二:使用shell中的let命令
let 'var3=var1+var2' #注意不能加'$'符号,否则报错
方法三:调用expr外部程序,效率较低,尽量少用
var3=$(expr $var1 + $var2) #expr函数需要三个参数,$var1,+,$var2
3.流程控制
1)if语句
结构如下:
if then elif then else fi
或者(then写在if的后面,但是要加分号;)
if ...;then elif...;then else fi
示例如下:
myshell
#!/bin/bash var1=1 var2=2 if ((var1==var2)) then echo "var1=var2" elif ((var1>var2)) then echo "var1>var2" else echo "var1<var2" fi
输出结果:
bash中有一些常用的条件判断表达式,使用方法:[ 条件判断表达式 ]
-f "filename":判断是否是文件
-x "/bin/ls":判断/bin/ls是否存在并有可执行权限
-n "$var":判断$var变量是否有值
"$a"=="$b":判断$a和$b是否相等
2)&&和||操作符
&&:逻辑与操作符
||: 逻辑或操作符
3)case语句
case表达式用来匹配给定的字符串,和C中的switch...case匹配的是数字不同。
case ... in ...) do something;; ...) do something;; esac
下例中,我们写了一个程序,用来解压bzip2,gzip,zip类型的压缩文件。
代码如下:
#!/bin/bash ftype=$(file $1) echo "$ftype" case "$ftype" in "$1: Zip archive"*) unzip "$1";; "$1: gzip compressed"*) gunzip "$1";; "$1: bzip2 compressed"*) bunzip2 "$1";; *) echo "File $1 can not be unconpressed";; esac
输出结果:
其中$1表示输入的第一个参数
4)select循环语句
select循环适合交互式的场合,格式如下:
select var in ...;do ... done
示例代码如下:
#!/bin/bash echo "what is your favourite OS?" select var in "RedHat" "Ubuntu" "Free BSD" "Other";do echo "hello $var" break; done echo "you have selected $var"
输出结果:
5)while/for循环
while循环
while...;do ... done
for循环
for var in ...;do ... done
示例代码如下:
#!/bin/bash for var in A B C;do echo "var is $var" done
输出结果:
4.shell里的一些特殊符号
1)*:表示通配符
双引号可以防止通配符但允许变量扩展
单引号(或转义字符)的限制更严格,可防止任何变量扩展;
示例代码如下:
#!/bin/bash echo *.c echo "*.c" echo '*.c' echo *.c echo $SHELL echo "$SHELL" echo '$SHELL' echo $SHELL
输出结果:
2)命令行参数
$1:命令行的第一个参数
$#:命令行参数的个数
$@:命令行的所有参数
$*:所有命令行参数作为一个参数
shift n:去掉前面的n个参数
示例如下:
#!/bin/bash help() { cat << HELP 本例程序用来获取命令行参数 使用了命令:myshell -l hello -f -- -somefile1 somefile2 HELP exit 0 } while [ -n "$1" ]; do case "$1" in -h) help;shift 1;; -f) opt_f=1;shift 1;; -l) opt_l=$2;shift 2;; --) shift;break;; -*) echo "error: no such option $1. -h for help";exit 1;; *) break;; esac done echo "opt_f is $opt_f" echo "opt_l is $opt_l" echo "first arg is $1" echo "2nd arg is $2"
输出结果:
3)输出段落
echo一次只能输出一行
如果是一段文字,该如何输出呢?
我们可以使用cat <<,后接一个字符串,段落的末尾再加上这个字符串来输出段落。
cat << HELP ... ... HELP
下例中,程序用来替换文件名,
有三个输入参数,第一个参数是待替换字符
第二个参数是替换字符
第三个参数是文件名。
#!/bin/bash if [ $# -lt 3 ];then cat << HELP 本例中,程序用来替换文件名, 有三个输入参数,第一个参数是待替换字符 第二个参数是替换字符 第三个参数是文件名。 HELP exit 0 fi OLD="$1" NEW="$2" # The shift command removes one argument from the list of # command line arguments. shift shift # $@ contains now all the files: for file in "$@"; do if [ -f "$file" ]; then newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"` if [ -f "$newfile" ]; then echo "ERROR: $newfile exists already" else echo "renaming $file to $newfile ..." mv "$file" "$newfile" fi fi done
输出结果:
5.函数
格式如下:
函数名(){ #函数中$1,$2对应接收到的第一第二个参数 }
示例代码如下:
#!/bin/bash add() { echo $(($1+$2)) } var1=1 var2=2 add $var1 $var2
输出结果:
四、脚本调试
最简单的方式是使用echo输出值。
五、Shell编程示例
我们有一个日志文件,保存了系统的操作记录。过了一段时间后,这个文件可能会变得很大。
我们采取的做法是重命名该文件,然后生成一个新的文件供再次使用。
重命名的规则是,当前文件log.txt重名为log1.txt,在此之前,如果已经有log1.txt时,将log。txt命名为log2.txt,依次类推。
代码如下:
#!/bin/bash help() { cat << HELP 重命名该文件,然后生成一个新的文件供再次使用。 重命名的规则是,当前文件log.txt重名为log1.txt,在此之前,如果已经有log1.txt时,将log。txt命名为log2.txt,依次类推。 HELP exit 0 } if [[ $1 == '-h' || $1 == '' ]]; then help fi filename=$1 # 我们先找到最大的数字再说。 max=0 while [ -f "$filename.$((++max))" ]; do : # 什么都不用做,我们已经顺手用 ++max 自增了 max 了。 done # 然后从最大的一路重命名下来。 for ((i=max; i>0; i--)); do # 数字加个 1,好给前一个让位子。 if [ -f $filename.$i ];then mv "$filename.$i" "$filename.$((i+1))" fi done # 最后我们点名要重命名的: if [ -f "$filename" ]; then mv "$filename" "$filename.1" fi # 重新创建一下。 : > "$filename"
运行程序,./myshell log.txt
我们会发现log.txt的日志文件的名称会加1,同时当前的log.txt文件会变成log.txt.1,
生成一个全新的log.txt文件,供程序再次使用。