- shell是unix和linux内核的外壳,它构成了命令或者程序的一个执行环境。不同版本的Unix和linux的shell各有特色,但是都提供了linux命令解释执行的一个基本工作环境。
- shell脚本程序是利用shell的语法功能所写的一个程序,它是一个纯文本文件,类似于windows环境下的.bat文件,可以让系统自动执行写在shell脚本中的命令,比起windows环境下的.bat文件,它更加类似于高级语言,它可以执行分支、循环、函数等功能。
- shell是一种解释型程序,不需要经过编译就可以执行。
- 在centos中执行shell脚本文件的时候,要注意linux并不会默认当前的路径为可以执行的目录,它的所有的可执行文件都会搜索系统的环境变量(可以使用
env | grep PATH
查询),环境变量PATH的值指定了可执行的文件的搜索路径。对于以上情况可以有以下的解决方案:
① 把当前路径变成可搜索路径(有风险)
② 把当前文件移动到可搜索路径下
③ 使用./filename
- 当前路径为可搜索路径后,可以直接输入还是会出错,以为没有执行的权限,有两种解决方法,
① chomd修改权限
② 使用sh filename
,把文件变成sh的一个参数输入
在shell中,所有的变量都没有定义变量类型,所有的变量都会被看做为字符串变量;在变量名前面加上美元符号
$
,可以引用变量的值。
[root@aubin s]# a=456 # 定义一个字符串变量a
[root@aubin s]# echo $a #把变量a的内容输出
456
echo表示输出一个数据
注意以下三条指令的不同
echo $a # 表示输出a这个变量
echo "$a" # 表示输出a这个变量
echo '$a' # 表示输出 $a 这个字符串
使用指令read
可以从键盘中输入一个变量的值,如下:
[cch@aubin s]$ read b
www
[cch@aubin s]$ echo 'b='$b
b=www
使用
[]
构成条件分支判断,if 和 fi是成对出现的,而且该语句不能随意的添加或者删减空格。
echo "Is it morning? Please answer yes or no!"
read timeofday
if [$timeofday="yes"];then
echo "Good morning!"
else
echo "Good afternoon!"
fi
exit 0
如果then
是单独一行,可以不用分隔符
echo "Is it morning? Please answer yes or no!"
read timeofday
if [$timeofday="yes"]
then
echo "Good morning!"
else
echo "Good afternoon!"
fi
exit 0
不使用中括号,使用test
也可以实现条件语句的编写,但是使用test没有方括号直观
echo "Is it morning? Please answer yes or no!"
read timeofday
if test $timeofday="yes"
then
echo "Good morning!"
else
echo "Good afternoon!"
fi
exit 0
多分支语句的编写可以使用elif
echo "Is it morning? Please answer yes or no!"
read timeofday
if [$timeofday="yes"]
then
echo "Good morning!"
elif [$timeofday="no"]
then
echo "Good afternoon!"
else
echo "The answer can not recognize, plese enter again!"
fi
exit 0
判断文件
if [ -f ./pp ] # 判断文件是否存在
then
echo "pp exists"
fi
if [ -d ./pp ] # 判断文件是否是一个目录,注意中括号与周围的空格
then
echo "pp is a directory"
else
echo "pp is a file"
fi
exit 0
if/while语句可以使用以下几种类型的判断
- 数值比较:-eq(等于)、-ne(不等于)、-gt(大于)、-ge(大于等于)、-lt(小于)、-le(小于等于)
- 字符串比较:=(等于)、!=(不等于)、-z(字符串长度为零)、-n(字符串长度不为零)
- 文件测试:-e(文件存在)、-d(目录存在)、-f(文件是否为文本)、-r/-w/-x(文件是否可读/可写/可执行)
- 逻辑运算:&&(与)、||(或)
- 其他特殊操作符:()(子shell)、[](数组)
case语句更加适用于多分支语句中
echo "Is it morning? Please answer yes or no"
read timeofday
case "$timeofday" in
"yes" ) echo "Good Morning";;
"no" ) echo "Good Afternoon";;
* ) echo "Please enter again";;
esac
exit 0
多个值匹配
echo "Is it morning? Please answer yes or no"
read timeofday
case "$timeofday" in
yes | Yes | Y ) echo "Good Morning";;
n* | N* ) echo "Good Afternoon";;
* ) echo "Please enter again";;
esac
exit 0
使用正则表达式
echo "Is it morning? Please answer yes or no"
read timeofday
case "$timeofday" in
[Yy][Ee][sS]| [Yy] ) echo "Good Morning";;
[nN][oO] |[Nn] ) echo "Good Afternoon";;
* ) echo "Please enter again";;
esac
exit 0
foo
是一个循环变量,in
是关键字,in后面的内容表示循环每一次的值,前面说到,shell的变量都是字符串,所以要循环什么就要在in后面写什么。do …… done
中间的表示循环体
for foo in 1 2 34 # 一共循环三次,in 后面的是循环变量的取值,都为字符串
do
echo $foo
done
exit 0
$(...)
,以…中的命令的执行结果作为shell变量的取值;除了使用以上的形式,还可以使用esc下面的单引号包括住所需要执行的命令。
for fo in $(ls p*)
do
echo $fo
done
exit 0
for fo in `ls p*`
do
echo $fo
done
exit 0
echo "Action!"
read temp
while [ "$temp" != "hello" ]
do
echo "Plase enter again!"
read temp
done
echo $temp
exit 0
分支判断采用表达式值的判断方式
-le
表示小于等于
foo=1
while [ "$foo" -le 20 ]
do
echo " $foo : Try again "
foo=$(($foo + 1))
done
exit 0
跳出循环
- break:跳出当前循环(break默认表示跳出一层循环,break2表示跳出两层循环)
- exit:退出当前脚本,不再执行exit下方的任何语句
- continue:忽略本次循环结果,继续执行循环
位置参数是指函数调用是参数的位置决定其对应的值,在shell中,位置参数从$1开始
- 无论是函数内部还是函数的外部, $0都表示程序名
$@或者$*
可以一次性获取所有的参数;$#
获取参数的个数${10}
获取第10个参数
# $0表示函数名; $1表示程序的第一个参数,$i表示程序的第i个参数;参数与其在命令行的位置有关
echo $0 $1
# 例如 ls -la 的命令,$0=ls $1=-la
代码示例1:
#! /bin/bash
# 这里表示命令行的位置参数,从命令行内键入
echo $0
echo $1
echo $2
echo $3
foo()
{
# 这里表示函数的位置参数,从函数调用中键入
echo $0
echo $1
echo $2
echo $3
echo $4
echo "function foo\n"
}
echo "---start---"
foo 11 22 33 44
#foo $0 $1 $2 $3 $4
echo "---end---"
# 输出结果
[cch@aubin s]$ ./pp aa bb cc dd
./pp
aa
bb
cc
---start---
./pp
11
22
33
44
function foo\n
---end---
[cch@aubin s]$
代码示例2:
#! /bin/bash
echo $0
echo $1
echo $2
echo $3
foo()
{
echo $0
echo $1
echo $2
echo $3
echo $4
echo "function foo\n"
}
echo "---start---"
#foo 11 22 33 44
foo $0 $1 $2 $3 $4 # 这里调用的是命令行的位置参数,从命令行中键入,把命令行中的参数作为函数的参数给函数foo调用
echo "---end---"
# 输出结果
[cch@aubin s]$ ./pp aa bb cc dd
./pp
aa
bb
cc
---start---
./pp
./pp # $1的输入结果
aa
bb
cc
function foo\n
---end---
[cch@aubin s]$
fun(){}
表示是一个函数,大括号之间的内容表示是一个函数体
fun(){
echo "This is fun function!"
}
echo "starting"
fun # 程序本身不会执行,只有当被调用才会开始执行
echo "ending"
exit 0
传递参数
fun(){
echo "This is fun function!"
echo $1 # 获取位置参数,表示是函数内的第一个参数
}
echo "starting"
fun "data"
echo "ending"
exit 0
# 这里是输出的结果
[cch@aubin s]$ ./pp
starting
This is fun function!
data
ending
注意,程序的位置参数与函数内的位置参数不是一个概念,出现在函数调用中的
$1
表示的是程序的位置参数,与在命令行中的第一个参数是一样的;
fun(){
echo "This is fun function!"
echo $2 # 获取位置参数
}
echo "starting"
fun "data" $1 #表示命令行的第一个位置参数
echo "ending"
exit 0
# 这里是输出的结果
[cch@aubin s]$ ./pp
starting
This is fun function! # 空行表示没有第二个命令参数
ending
- sed是一个“流编辑”工具,它不面向屏幕,而且非交互式。流编辑器非常适合于执行重复的编辑,这种重复的编辑如果由人工完成将花费大量的时间。
- sed使用工具按照顺序逐行将文件读入到内存中,然后,他执行该行的所有指定的操作,并且在完成请求的修改之后将该行返回内存中,以将其转储到中断。完成这一行的所有操作之后,它读取文件的下一行,重复以上步骤,知道它完成整个文件。sed默认把内容输出到屏幕,保持源文件不会被修改。
sed的语法:
sed [options] '{command}' [filename]
-e 表示后面的指令同步执行
[cch@aubin ~]$ echo "the tiger cubs will meet on Tuesday after scool" | sed -e 's/tiger/wolf/' -e 's/after/before/'
the wolf cubs will meet on Tuesday before scool
awk是一个优秀的样式扫描与处理工具,其功能大大强与sed和grep;awk几乎可以完成grep和sed所能完成的全部的工作,同时它号可以进行样式的装入、流控制、数学运算符、进程控制语句甚至内置的变量和函数。它具备了一个完整的语言所应该具备的几乎所有的特性。awk有自己的程序设计语言为 样式扫描和处理语言。
awk [-F separator] ‘pattern’ {action}’ filename
$1 表示第一列的意思,匹配搭配 :0 行,并且输出第一列的信息
[cch@aubin ~]$ who | awk '/:0 /{print $1}'
cch
which主要是用来查找一些可执行文件的存放在哪一个可执行的路径下。
[cch@aubin ~]$ which file
/usr/bin/file
# 以上系统命令可以使用sed来实现
for i in `env | grep PATH | sed -e 's/^PATH=//' -e 's/:/ /g'`
do
find $i -name $1 -print 2>/dev/null
done
[cch@aubin s]$ ./pp file
/usr/bin/file
[cch@aubin s]$
以上命令的意思是:
- `表示单引号内的都是可执行的命令
env
是一个系统命令,用于查找当前系统的可执行路径env | grep PATH | sed
,把env的结果作为右边的输入,检查env输出中的PATH匹配项,并且给到sed-e
表示两个指令同步执行's/^PATH=//'
把首字串为PATH=的替换成空's/:/ /g'
把所有的冒号替换成空格,并且全文替换。find $i -name $1 -print
把输入的第一个参数作为find的查找,去查找到对应的结果并且输出2>/dev/null
可能会出现错误,把错误重定向/dev/null中,避免屏幕显示出错误
# 还可以使用awk来实现,awk有内嵌的函数
for i in `set | grep PATH |awk '{sub(/^PATH=/,"")}{gsub(/:/," ")}{print $0}'`
do
find $i -name $1 -print 2>/dev/null
done
exit 0
以上的命令解释如下:
sub
和gsub
是awk内嵌的两个函数,前者表示替换,后者表示全文替换{print $0}
表示输出全部的列,作为in 后面的内容set
与env的命令是一样的
问题一:如何定义和使用shell变量,给出一个例子
讨论:使用shell变量有三种方法,一种是用等号直接赋值,比如a=123;第二种是从键盘中读入,比如read b;第三种是使用for循环变量,比如 for i in a b c,可以对i循环赋值为a b c。
问题二:if/while语句可以利用多少种类型的判断?
讨论:if/while语句可以有三种类型的判断,一种是字符串的判断,比如判断写入的数据是否是yes/no;第二种是文件的判断,比如使用 -f 判断文件是否存在,使用 -d 判断文件是否是一个目录;第三种是判断一个值是否相等,shell变量虽然都是字符串,但是可以使用$()对字符串取值。
问题三:什么是正则表达式,怎么样使用正则表达式去匹配得更加清楚
讨论:正则表达式可以用来匹配符合某一种规则的字符,以case语句中,需要匹配no的各种大小写的可能性,可以使用正则匹配 [Nn][Oo] | [Nn] ,这样可以使得条件表达式更加简洁。
问题四:程序(可执行文件)的参数是什么,函数的参数是什么,举例说明如何使用这些参数。
讨论:程序的位置参数和函数的位置参数是不同的,①程序的参数指的是整一个程序(命令的)参数,比如在命令行中输入ls -la ,该命令中的 -la 就是该命令的第一个参数,用 $1 表示;②函数的参数表示函数调用时传递的参数,跟在函数调用的后面。
问题五:什么是sed,什么是awk,举例说明怎么使用他们
讨论:详情看上面的介绍。