1.什么是shell
1)shell是一个作为用户与linux系统间接口的程序,它允许用户向操作系统输入需要执行的命令。
在大多数Linux发行版中,默认的shell程序/bin/sh实际上是对程序/bin/bash的一个连接
查看bash的版本号:/bin/bash --version
2)shell程序是解释型的程序,简单,可移植,开发容易,缺点是效率不如编译型语言
3)关于第一行的#!
告知unix内核应该以哪个shell来执行指定的脚本
如:
#! /bin/sh - (选项-表示没有shell选项)
4)shell识别三种基本命令:内建命令,shell函数以及外部命令
内建命令:就是shell本身所执行的命令,如cd,test命令,echo,printf
shell函数:以shell语言写成,可以像命令那样引用
外部命令:由shell的副本(新的进程)所执行的命令
2.管道和重定向
1)重定向输出
ls -l > output.txt 把ls命令的输出保存到文件output.txt中(默认情况下,如果该文件已经存在,它的内容将被覆盖)
ls -l >> output.txt 把ls命令的输出附加到文件output.txt的尾部
kill -HUP 1234 >killout.txt 2>killerr.txt 把标准输出和标准错误输出分别重定向到不同的文件中
kill -HUP 1234 >killout.txt 2>&1 把标准输出和标准错误输出都重定向到同一个文件killout.txt
2)重定向输入
more < killout.txt
3)管道
可以用管道操作符|来连接进程(允许连接的进程数目没有限制),在linux下通过管道连接的进程可以同时运行,并且随着数据流在它们之间的传递可以自动进行协调
ps -xo comm | sort | uniq | grep -v sh | more(查看系统中运行的所有进程的名字,但是不包括shell)
命令含义:首先按字母顺序排序ps命令输出,再用uniq去除相同名字的进程,然后通过grep -v sh删除名为sh的进程,最终将结果分页显示在屏幕上
3.shell脚本的执行方法
一,执行脚本过程中可能遇到的错误及解决方案
在linux中执行shell脚本时,可能遇到以下的错误:
1)报错:/bin/sh^M: bad interpreter: Nosuchfileordirectory。
原因:这个应该是将windows下写的脚本放到linux下执行,脚本的格式为dos格式的
可以先看看脚本是否为dos格式,方法如下:
vi 脚本名
:set ff
如果是dos格式,可以通过dos2unix 命令转换(也可以通过:set ff=unix 或 :set fileformat=unix)
dos2unix 脚本名
2)执行脚本时,会报第一行有错误,但是程序会执行后面的处理(如:#!/bin/sh 有问题),可以查看下文件格式
file 脚本名
如果文件格式为UTF-8的,可以看看它是不是带BOM头的。如果是带BOM头的,那就是出错原因。将脚本的BOM头去掉
二、执行方法
1)source 或者.
例如执行setenv 脚本 ,可以使用source setenv 或者. setenv
说明:source的程序主体是bash,脚本中的$0变量的值是bash,而且由于作用于当前bash环境,脚本中set的变量将直接起效
2)/bin/sh
例如 /bin/sh setenv
说明:打开一个子shell来读取并执行脚本中命令。该脚本文件可以无"执行权限"
由于是在子shell中执行,脚本设置的变量不会影响当前shell
3)./
这个命令执行脚本,需要脚本程序是可以执行的,可以通过chmod对文件模式进行修改。然后执行./setenv
说明:打开一个子shell来读取并执行FileName中命令。该filename文件需要"执行权限"
由于是在子shell中执行,脚本设置的变量不会影响当前shell
4.shell语法
一、基础知识
1.关于变量
1)shell中,变量的值可以为空值,也就是null
2)取出shell变量的值时,需要于变量名称前面加上$
3)给变量赋值时,值内含有空格,需要加上引号
4)当变量作为第二个变量的新值时,不需要用双引号,当将几个变量连接起来时要用双引号
oldname = $fullname (不需要双引号,用双引号也没有关系)
fulname = "$first $second $third"
5)变量中引号的使用
如果变量中包含空白字符,就必须给变量参数加上引号
如果把一个$变量表达式放在双引号中,程序执行到这一行时就会把变量替换为它的值;如果把它放在单引号中,就不会发生替换现象
可以通过在$前加上转义字符取消它的特殊含义
6)环境变量
主要的环境变量如下:
$HOME 当前用户的家目录
$PATH 以冒号分隔的用来搜索命令的目录列表
$PS1 命令提示符,通常是$,在bash中你可以使用一些更加复杂的值
$PS2 二级提示符,用来提示后续的输入,通常是>
$IFS 输入域分隔符。当shell读取输入时,它给出用来分隔单词的一组字符,它们通常是空格,制表符和换行符
$0 shell脚本的名字
$# 传递给脚本的参数个数
$$ shell脚本的进程号,脚本程序通常会用它来生成一个唯一的临时文件,如/tmp/tmpfile_$$
7)参数变量
如果脚本程序在调用时带有参数,一些额外的变量就会被创建。
参数变量如下:
$1,$2,…… 脚本程序的参数
$* 在一个变量中列出所有的参数,各个参数之间用环境变量$IFS中的第一个字符分隔
$@ 它是$*的一种精巧变体,它不使用IFS环境变量,所以即使IFS为空,参数也不会挤在一起
$! Shell最后运行的后台Process的PID
$? 最后运行的命令的结束代码(返回值)
$0 Shell本身的文件名
$# 是传给脚本的参数个数
2.打印语句
echo
echo将各个参数打印到标准输出,参数之间用空格隔开,并以换行符结束。它会解释每个字符串里的转义序列
printf
printf可以进行格式化输出,基本完全复制C,C++中printf的功能
$printf "the first program:%s,%s!" Hellord World
$the first program:Hellord, World!
二、条件
1)shell的布尔判断命令[或者test
当使用[命令时,还要使用]来结尾
举例如下
if test -f fred.c
then
……
fi
或者(必须在[符号和被检查的条件之间留出空格,也就是要把[符号看作和test命令一样)
if [ -f fred.c ]
then
……
fi
如果要将then和if放在同一行,需要用一个分号将test语句和then分隔,如
if [ -f fred.c ]; then
……
fi
2)test命令可以使用的条件类型:字符串比较,算术比较,文件条件测试
字符串比较:
string1 = string2 如果两个字符串相同则为真
string1 != string2 如果两个字符串不相同则为真
-n string 如果字符串不为空则结果为真
-z string 如果字符串为null(一个空串)则为真
算术比较:
expression1 -eq expression2 如果两个表达式相等则结果为真
expression1 -ne expression2 如果两个表达式不相等则结果为真
expression1 -gt expression2 如果expression1大于expression2则结果为真
expression1 -ge expression2 如果expression1大于等于expression2则结果为真
expression1 -lt expression2 如果expression1小于expression2则结果为真
expression1 -le expression2 如果expression1小于等于expression2则结果为真
!expression 如果表达式为假则结果为真,反之亦然
文件条件测试:
-d file 如果文件是一个目录则结果为真
-e file 如果文件存在则结果为真
-f file 如果文件是一个普通文件则结果为真
-g file 如果文件的set-group-id(也叫set-gid)位被设置则结果为真
-r file 如果文件可读则结果为真
-s file 如果文件的大小不为0则结果为真
-u file 如果文件的set-user-id(也叫set-uid)位被设置则结果为真
-w file 如果文件可写则结果为真
-x file 如果文件可执行则结果为真
三,控制结构
1)if语句(可以使用elif)
if condition
then
statements
elif
statements
else
statements
fi
2)for语句
for variable in values
do
statements
done
3)while语句(条件为真时反复执行)
while condition
do
statements
done
4)until语句(循环将反复执行直到条件为真)
until condition
do
statements
done
5)case语句(case语句是按顺序比较每一个字符串,它不会去查找最佳匹配,而仅仅是查找第一个匹配)
case variable in
pattern [ | pattern]……) statements;;
pattern [ | pattern]……) statements;;
……
esac
四、命令
下面是关于几个命令的说明
1):命令
冒号(:)是一个空命令。它偶尔会被用来简化条件逻辑,相当于true的一个别名。由于它是内置命令,所以它运行的比true快,但输出可读性差
while :实现一个死循环,代替更常见的while true
:结构也会被用在变量的条件设置中,例如: :${var:=value}
2).命令
点命令用于在当前shell中执行命令:. ./shell_script
3)eval 命令
eval命令允许你对参数进行求值。它是shell的内置命令
4)export命令
export命令将作为它参数的变量导出到子shell中,并使之在子shell中有效。
一旦一个变量被shell导出,它就可以被该shell调用的任何脚本使用,也可以被后续依次调用的任何shell使用
5)return命令
return命令的作用是使函数返回。return后面有个数值参数,表示该函数的返回值。如果return没有参数,则return默认返回最后一条命令的退出码
6)set命令
set命令的作用是为shell设置参数变量。还可以通过set命令和它的参数来控制shell的执行方式。如常用的命令:set -x(它让一个脚本程序跟踪显示它当前执行的命令)
7)unset命令
unset命令的作用是从环境中删除变量或函数
8)shift命令
shift命令把所有的参数变量左移一个位置,使$2变成$1,$3变成$2,以此类推。原来$1的值将被丢弃,而$0仍保持不变。如果调用shift命令时指定了一个数值参数,则表示所有的参数将左移指定的次数。$*,$@,$#等其他变量也将根据参数变量的新安排做相应的变动
五,正则表达式
下面介绍一些基础的正则表达式的基础知识
1)最常用的特殊字符
^ 指向一行的开头
$ 指向一行的结尾
. 任意单个字符
[] 包含一个字符范围,其中任何一个字符都可以被匹配,例如字符范围a~e,或在字符范围前面加上^符号表示 使用反向字符范围,即不匹配指定范围内的字符
说明:如果想将以上的字符作为普通字符使用,需要在这些字符前面加上字符
在方括号中还可以使用一些有用的特殊匹配模式,如下:
[:alnum:] 字母与数字字符
[:alpha:] 字母
[:ascii:] ASCII字符
[:blank:] 空格或制表符
[:cntrl:] ASCII控制字符
[:digit:] 数字
[:graph:] 非控制,非空格字符
[:lower:] 小写字母
[:print:] 可打印字符
[:punct:] 标点符号字符
[:space:] 空白字符,包括垂直制表符
[:upper:] 大写字母
[:xdigit:] 十六进制数字
正则表达式匹配规则
? 匹配是可选项,但最多匹配一次
* 必须匹配0次或多次
+ 必须匹配1次或多次
{n} 必须匹配n次
{n,} 必须匹配n次或n次以上
{n,m} 匹配次数在n到m之间,包括n和m
六、脚本程式的调试
出现错误时,shell一般会打印包含错误的行号。如果这个错误并不是很明显,可以添加一些额外的echo语句来显示变量的内容,也可以通过在shell中交互式的输入代码片段来对进行测试。
跟踪脚本程序中复杂错误的主要方法是设置shell选项。可以在调用shell时加上命令行选项或者使用set命令
以下列出各种选项。
命令行选项 set选项 说明
sh -n <script> set -o noexec 只检查语法错误,不执行命令
set -n
sh -v <script> set -o verbose 在执行命令之前回显它们
set -v
sh -x <script> set -o xtrace 在处理完命令之后回显它们
set -x 可在脚本中加入此句,打开跟踪功能
set +x 可在脚本中加入此句,关闭跟踪功能
sh -u <script> set -o nounset 如果使用了未定义的变量,就给出出错消息
set -u