shell是一个命令解释器,位于操作系统的最外层,它负责和用户直接对话,不用户输入的内容解释给操作系统,操作系统处理完毕后,输出结果,输出到屏幕上。分为交互式的和非交互式的。输入命令,得到结果。就是交互式的,执行脚本就是非交互的。
总结:shell就像是一座桥梁,连通用户和操作系统。
把一个或多个linux命令组合起来放在一个程序文件中执行,这样的程序叫做shell脚本。严格来说把命令.变量和流程控制语句等结合在一起,就是shell脚本
要多去模拟操作,多去想想为什么
linux中所有的配置文件.日志文件都是纯文本文件。而shell的特点就是善于处理纯文本的内容。
bourne shell(包括 sh,ksh,bash) C shell(csh,tcsh)
查看系统支持的sh类型:/etc/shells,常用的就是/bin/sh,/bin/bash,/sbin/nologin
Linux主流的shell就是bash,它是bourne again shell的缩写,是由bonrne shell发展而来,它还包含了csh和ksh的特色。
目前:通用的bourne shell 已经被bash shell取代
Linux:bash
solaris:bonrne sh
AIX:ksh
HP-unix:posix shell(sh)
可以修改/etc/default/useradd文件的shell字段,更改新添加的用户。也可以直接修改/etc/passwd中的最后一个字段,直接修改某个用户的shell。
通过vim编辑器编写shell脚本 ,注意脚本的第一行 #!/bin/bash 表示来指定解释器
注意:python 程序开头 #!/usr/bin/env python因为Linux默认就是使用bash,所以使用bash的话,可以不用加,为了规范还是要添加。如果不指定解释器,就需要用bash test.sh来执行了。
注意:写脚本要写注释
当shell运行时,它会先查找系统环境变量ENV,该变量指定了环境文件(通常是.bashrc,.bash_profile,/etc/bashrc,/etc/profile等),然后从该环境变量文件开始执行脚本,当读取了ENV的文件后,shell会开始执行shell脚本中的内容。
注意:设置cron任务时,最好把系统变量在脚本中重新定义一遍
shell脚本的执行通常采用以下几种方式
注意:我们用户登录的时候会默认分配一个shell,这个shell就是父shell,而在这个shell中执行的shell脚本,就属于子shell,父shell是不能直接继承子shell的变量的,但子shell可以直接继承父shell的变量,如果想要父shell获取子shell中的变量,就需要使用source或者.来执行脚本了。(相当于php中的include)
#!/bin/bash或者#!/bin/sh
#Date:
#Author: create by lixin
#Mail:
#Function:功能
比如x=1,y=x+1,那么y等于2。x和y就是变量名,x变量的值是1,而y变量的值是x+1,等号在这里叫做赋值。
简单的说,变量就是用一个固定的字符串(也可能是字符数字等的组合),代替更多更复杂的内容,这个内容里可能还会包含变量.路径.字符串等其他的内容。
变量是暂时存数据的地方,这个存储的数据是存在于内存空间中的,通过调用变量的名字就可以取出变量对应的数据。
bash shell中默认的情况下是不会区分变量的内容的类型,例如:整数.字符串.小数等。这一点和其他强类型语言是有区别的。如果需要指定shell变量内容类型,可以使用declare显示指定定义变量的类型(没这个需求)。
变量可以分为:环境变量(全局变量)和普通变量(局部变量)。
环境变量也成为全局变量,可以在创建他们的shell及其派生出来的任意子进程shell中使用,环境变量又可以分为自定义环境变量和bash内置的环境变量。
普通变量也可成为局部变量,只能在创建他们的shll函数或shell脚本中使用。普通变量一般是由开发者在开发脚本程序时创建的。
环境变量一般用于定义shell的运行环境,保证shell命令的正确执行,shell通过环境变量来确定登录用户名.命令路径.终端类型.登录目录的等,所有的环境变量都是系统全局变量,可用于所有子进程中,这包括编辑器.shell脚本和各类应用(cron任务比较特殊需要注意)。
环境变量可以在命令行中设置创建,但用户退出命令是这些变量值就会丢失,因此,如果希望永久保存环境变量,可以在用户家目录下.bash_profile或.bashrc文件或全部配置文件/etc/profile或/etc/bashrc文件或者/etc/profile.d/下定义,因为每次用户登录时这些变量的值都会被初始化一次。
所有环境变量名字格式均为大写,环境变量用于用户进程程序前,都应该用export命令导出定义,例如:export KEY=1.
环境变量可以在创建他们的shell和从该shell派生的任意子shell或进程中,他们通常被称为全局变量以区别局部变量。通常,环境变量应该大写。环境变量是已经用export内置命令导出的变量。
有一些环境变量,比如HMOE.PATH.SHELL.UID.USER等,在用户登录之前就已经被/bin/login程序设置好了,通常环境变量定义并保存在用户家目录下的.bash_profile中。
通过echo或printf命令打印环境变量
例:
打印用户登录的目录: echo $HOME
打印用户的UID: printf $UID
使用env和set命令查看所有的环境变量
通过unset命令取消环境变量: unset NAME
本地变量再用户当前的shell生存期的脚本中使用,例如,本地变量key的取值为123,这个值只在用户当前shell生存期中有意义。如果在shell中启动另一个进程或退出,本地变量key值将无效。
定义普通变量的方法:
其中,变量名一般是有字符,数字,下划线组成。可以字符或下划线开头,但是不能以数字开头。
变量的内容,可以用单引号或双引号引起来,或不加引号。三者的区别是;不加引号,不能输入不连续的值,只要变量连续,可以解释其中引用的其他变量。单引号和echo中的单引号相同,就是内部有变量则不会解释变量,双引号即如果定义的值中引用其他变量,则解释该变量,变量的值可以是不连续的。而反引号,一般用来解析命令,相当于$().
例子:
a=192.168.1.2
b='192.168.1.2-$a'
c="192.168.1.2-$a"
echo $a
192.168.1.2
echo $b
192.168.1.2-$a
echo $c
192.168.1.2-192.168.1.2
a=192.168.1.2-$a
b='192.168.1.2-$a'
c="192.168.1.2-$a"
echo $a
192.168.1.2-192.168.1.2
echo $b
192.168.1.2-$a
echo $c
192.168.1.2-192.168.1.2-192.168.1.2
注意:日常定义变量如果是纯数字的话可以不加引号,其他情况建议都使用双引号。
扩展:把命令的结果作为变量
变量名=`ls`或者 变量名=$(ls)
定义变量后可以直接在各个地方调用
key=init
grep $key /etc/iniitab
grep "$key" /etc/inittab
# 上面两个会过滤出/etc/inittab中包含init字符串的行
grep '$key' /etc/inittab
# 单引号,则会过滤出/etc/inittab中包含$key的行,同样适用于sed。
注意:awk中不同于grep和sed中
awk中的特殊用法1:
key=init
awk 'BEGIN{print "$key"}'
# awk中""是不解释变量的,和常规的相反,只有使用单引号才会解析。
awk 'BEGIN{print '$key'}'
# 不加引号,则不会输出
awk中的特殊用法2:
key='int'
awk 'BEGIN{print '$key'}'
# 这时也是不会输出内容的,需要在单引号外面再加一层双引号才可以
awk 'BEGIN{print "'$key'"}'
KaTeX parse error: Expected group after '_' at position 2: 0_̲_ 获取当前执行的shell脚…n 获取当前执行的shell脚本的第n个参数的值,n=1…9,当n为0时表示脚本的文件名,如果n大于9,用大括号括起来${10}.例子:
# 创建测试文件:
[root@CentOS6 ~]# echo -n 'echo ' > test1.sh && echo \${1..15} >> test.sh
[root@CentOS6 ~]# cat test.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15 $16
[root@CentOS6 ~]# bash test.sh {a..z}
a b c d e f g h i a0 a1 a2 a3 a4 a5 a6
# 由于变量超过了9个,所以从第10个变量开始要加大括号,不然shell认为$10,是$1的值和0组合在一起,所以才会显示a0
[root@CentOS6 ~]# cat test.sh
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ${15} ${16}
[root@CentOS6 ~]# bash test.sh {a..z}
a b c d e f g h i j k l m n o p
# $# 表示脚本传参的个数,脚本名称后面的参数的个数.
# $* 将命令行脚本所有参数视为单个字符串等同于"$1$2$3",$*要用双引号。
# $@ 将命令行脚本每个参数视为单独的字符串,等同于"$1","$2","$3",这是将参数传递给其他程序的最佳方式,因为他会保留所有内嵌在每个参数里的任何空白。
# 注意:上述区别仅限于添加双引号的时候,即"$*"和$"@"
例:
[root@CentOS6 scripts]# set -- a b c
[root@CentOS6 scripts]# for i in "$@" ;do echo $i; done;
a
b
c
[root@CentOS6 scripts]# for i in "$*" ;do echo $i; done;
a b c
[root@CentOS6 scripts]#
$? 查看上一个命令的执行结果。0表示成功,非0表示不成功。
错误代码返回值参考:
2:权限不够
1-125:表示运行失败(脚本命令.系统命令错误或参数传递错误)
126:找到该命令了,但无法执行
127:命令找不到
128:被强制中断了
注意:在shell脚本中一般用exit 数字,来把返回值传递给 ? 如 果 是 函 数 , 则 通 过 r e t u r n 数 字 , 返 回 返 回 值 给 ? 如果是函数,则通过return 数字,返回返回值给 ?如果是函数,则通过return数字,返回返回值给?
扩展:通过set命令进传参
http://httpd.blog.51cto.com/2561410/1175971
set -- 'i am' handsome boy 传递3个参数到shell
set -- 1 2 3
[root@CentOS6 ~]# echo $1 $2 $3
1 2 3
# $$ 显示当前进程的进程号
# $! 上一个进程的id号
cat pid.sh
echo $$ >/tmp/a.pid
sleep 300
sh pid.sh &
cat /tmp/a.pid
bash的内置命令,这些命令内置在bash中,没有绝对路径,需要时可以直接在shell脚本中调用 alias, bg, bind, break, builtin, caller, cd,command, compgen, complete, compopt, continue, declare, dirs,disown, echo, enable, eval, exec, exit, export, false, fc,fg, getopts, hash, help, history, jobs, kill, let, local,logout, mapfile, popd, printf, pushd, pwd, read, readonly,return, set, shift, shopt, source, suspend, test, times,trap, true, type, typeset, ulimit, umask, unalias, unset,wait
通过man bash找到Parameter Expansion来查看子串的全部用法
${#变量名}取变量的长度
[root@CentOS6 ~]# httpd="I am httpd"
[root@CentOS6 ~]# echo $httpd
I am httpd
[root@CentOS6 ~]# echo $httpd|wc -L
11
[root@CentOS6 ~]# echo ${#httpd}
11
通过使用expr命令计算变量的长度
[root@CentOS6 ~]# expr length "$httpd"
11
# 计算I am good boy,welcome to myhome中字母小于5个的并打印
for i in I am good boy,welcome to myhome
do
[ ${#i} -lt 5 ] &&{
echo "$i"
}
done
${变量:2}截取变量的第几个字符到最后
[root@CentOS6 ~]# httpd="I am httpd"
[root@CentOS6 ~]# echo ${httpd:2}
am httpd
[root@CentOS6 ~]# echo ${httpd:3}
m httpd
${#变量:n:m}从第n个字符开始截取m个
[root@CentOS6 ~]# echo ${httpd:2:2}
am
${变量#字符串}从开头开始匹配,删除最短匹配字符串的值
[root@CentOS6 scripts]# echo $LIXIN
123123123123123123123123456
[root@CentOS6 scripts]# echo ${LIXIN#1*3}
123123123123123123123456
${变量##字符串}从开头开始匹配,删除最长匹配字符串的值
[root@CentOS6 scripts]# echo ${LIXIN##1*3}
456
[root@CentOS6 scripts]# echo $LIXIN
i am good boy boy
[root@CentOS6 scripts]# echo ${LIXIN%b*y}
i am good boy
[root@CentOS6 scripts]# echo ${LIXIN%%b*y}
i am good
[root@CentOS6 scripts]#
小结:
- #是开头删除匹配最短
- ##是开头删除匹配最长
- %是结尾删除匹配最短
- %%是结尾删除匹配最长
${变量/字符串1/字符串2},从开头开始,把变量中的字符串1替换为字符串2.
[root@CentOS6 scripts]# LIXIN="i am good boy boy"
[root@CentOS6 scripts]# echo $LIXIN
i am good boy boy
[root@CentOS6 scripts]# echo ${LIXIN/boy/girl}
i am good girl boy
[root@CentOS6 scripts]# echo ${LIXIN//boy/girl}
i am good girl girl
两个斜线表示替换所有符合的字符串
[root@CentOS6 scripts]# echo ${LIXIN/#boy/girl}
i am good boy boy
#表示以boy开头的,替换为girl,由于变量LIXIN没有以boy开头,所以不会替换
[root@CentOS6 scripts]# echo ${LIXIN/%boy/girl}
i am good boy girl
[root@CentOS6 scripts]#
${values:-word} 如果变量名称存在并且非null,则返回变量的值。否则返回word字符串,表示如果变量未定义,则返回默认值。
[root@CentOS6 scripts]# echo ${lixin:-test}
test
[root@CentOS6 scripts]# lixin=123
[root@CentOS6 scripts]# echo ${lixin:-test}
123
[root@CentOS6 scripts]# echo $lixin
空
${value:=word} 如果变量名存在且非null,则返回变量值。否则,设置这个变量为word,并返回其值
[root@CentOS6 scripts]# echo ${lixin:=test}
test
[root@CentOS6 scripts]# echo $lixin
test
[root@CentOS6 scripts]#
注意:-和=的区别是,-表示变量为空的时候返回的默认值,这个默认值并不会被赋予变量,所以echo变量的时候依旧为空,=表示如果变量为空,则把word赋予该变量。
扩展:这个冒号:也可以不加,功能和加上是相同的
[root@CentOS6 scripts]# unset LIXIN
[root@CentOS6 scripts]# echo ${LIXIN-test}
test
[root@CentOS6 scripts]# LIXIN=1
[root@CentOS6 scripts]# echo ${LIXIN-test}
1
[root@CentOS6 scripts]#
[root@CentOS6 scripts]# unset LIXIN
[root@CentOS6 scripts]# echo ${LIXIN=test}
test
[root@CentOS6 scripts]# echo $LIXIN
test
[root@CentOS6 scripts]#
变量的数值计算常见的有如下几个命令:(()),let,expr,bc(小数运算),${},其他都是整数。
常用运算符号:
1.(())用法
如果要执行简单的整数就算,只需要将特定的算数表达式用$(())括起来即可。
[root@CentOS6 scripts]# echo $((1+2))
3
[root@CentOS6 scripts]# echo $(1+2)
-bash: 1+2: command not found
[root@CentOS6 scripts]#
[root@CentOS6 scripts]# ((a=1+2**3-4%3))
[root@CentOS6 scripts]# echo $a
8
[root@CentOS6 scripts]#
+=例子:
[root@CentOS6 scripts]# echo $a
8
[root@CentOS6 scripts]# echo $((a+=1))
9
[root@CentOS6 scripts]# echo $a
9
[root@CentOS6 scripts]# echo $((a-=1))
8
[root@CentOS6 scripts]# echo $a
8
[root@CentOS6 scripts]#
n++例子:
[root@CentOS6 scripts]# echo $a
8
[root@CentOS6 scripts]# echo $((a++))
8
[root@CentOS6 scripts]# echo $a
9
[root@CentOS6 scripts]# echo $((a--))
9
[root@CentOS6 scripts]# echo $a
8
[root@CentOS6 scripts