Shell 基础介绍 [1]

Shell 基础介绍

Shell 基础介绍

shell

时间:2016年11月10日

首先在此感谢下我的老师-老男孩专家拥有16年一线实战经验,为我们运维班28期所有成员的耐心讲解,未经本人同意禁止转载

1.什么是Shell?

Shell是一个命令解释器,它在操作系统的最外层,负载直接与用户对话,把用户的输入解释给操作系统,并处理各种各样的操作系统的输出结果,输出到屏幕并返回给用户。这种对话方式可以是交互的方式(从键盘输入命令,可以立即得到shell的回应),或非交互式(执行脚本程序)的方式。

图解:

1.jpg-16.1kB

当linux命令或语句不在命令行下执行(严格说,命令行执行的语句也是shell脚本),而是通过一个程序文件执行时,该程序就被称为shell脚本或shell程序,shell程序很类似DOS系统下的批处理程序。这些命令、变量和流程控制语句结合起来就形成了一个功能强大的shell脚本

简单的小脚本

#!/bin/bash
  # 清除日志脚本, 版本 2
  LOG_DIR=/var/log
  ROOT_UID=0     # $UID为0的时候,用户才具有root用户的权限
# 要使用root用户来运行,因此,对当前用户进行判断,不合要求给出友好提示,并终止程序运行。
  if [ "$UID" -ne "$ROOT_UID" ]
then
     echo "Must be root to run this script."
     exit 1
  fi
# 如果切换到指定目录不成功,给出提示,并终止程序运行。
cd $LOG_DIR || {
    echo "Cannot change to necessary directory." >&2
    exit 1
  }
# 经过上述两个判断后,此处的用户权限和路径就应该是对的了,只有清空成功,才打印成功提示。
  cat /dev/null > messages &&{
echo "Logs cleaned up."
    exit 0  # 退出之前返回0表示成功. 返回1表示失败。
}
echo "Logs cleaned up fail."
  exit 1

1.必须是root才能执行脚本,否则给出友好提示并终止程序运行

2.成功切换目录(cd/var/log),否则给出友好提示并终止运行

3.清理日志(cat /dev/null >messages)清理成功,给出正确提示

4.给出相应提示(echo 输出)

Shell脚本语言擅长处理纯文本类型的数据,而linux系统中几乎所有的配置文件、日志文件(如nfs、rsync、httpd、nginx、lvs等)、绝大多数启动文件纯文件。就可以利用它在Linux系统中发挥巨大的作用。

image_1b16oaub2mv9phi1bm54m314eu2a.png-119.3kB

2.脚本语言类型

2.1 Shell脚本语言的种类

在UNIX/LINUX中主要由两大类shell

1.Bourne shell(包括sh、ksh、bash)

Bourne shell (sh)
Korn shell (ksh)
Bourne Again shell (bash)
POSIX shell (sh)

2. Cshell (包括csh、tcsh)

C shell (csh)
TENEX/TOPS C shell (tcsh)

Shell脚本语言是弱类型语言,较为通用的shell有标准的Bourne shell (sh)和C shell (csh)。其中Bourne shell (sh)已经被bash shell取代,但是我们还是习惯称之为sh

查看Centos6 系统SHELL情况:

[root@web02 ~]# cat /etc/shells 
/bin/sh  <==黄色标记为重点
/bin/bash
/sbin/nologin
/bin/dash
/bin/tcsh
/bin/csh

Linux系统中的主流shell是Bash,它是Bourne Again Shell的缩写,Bash是由Bourne Shell(sh)发展而来的,但Bash与sh稍有不同,它还包含了cshksh的特色,但大多数脚本可以不加修改地在sh上运行

3.其他常用的脚本语句种类

3.1 PHP

PHP是网页程序,也是脚本语言。是一款更专注于web页面开发(前端展示)的脚本语言,例如:Dedecms,discuz。PHP程序也可以处理系统日志,配置文件等,php也可以调用系统命令。

3.2 Perl

Perl脚本语言。比shell脚本强大很多,语法灵活、复杂,实现方式很多,不易读,团队协作困难,但仍不失为很好的脚本语言,存世大量的程序软件。MHA高可用Perl写的

3.3 Python

Python,不但可以做脚本程序开发,也可以实现web程序以及软件的开发。近两年越来越多的公司都会要求会Python。

Shell脚本与php/perl/python语言的区别和优势?

shell脚本的优势在于处理操作系统底层的业务 (linux系统内部的应用都是shell脚本完成)因为有大量的linux系统命令为它做支撑。2000多个命令都是shell脚本编程的有力支撑,特别是grepawksed等。例如:一键软件安装优化监控报警脚本,常规的业务应用,shell开发更简单快速,符合运维的简单、易用、高效原则.

PHP、Python优势在于开发运维工具以及web界面的管理工具,web业务的开发等。处理一键软件安装、优化,报警脚本。常规业务的应用等php/python也是能够做到的。但是开发效率和复杂比用shell就差很多了。

常用操作系统的默认shell

1.Linux是Bourne Again shell(bash)

2.Solaris和FreeBSD缺省的是Bourne shell(sh)

3.AIX下是Korn Shell(ksh)

4.HP-UX缺省的是POSIX shell(sh)

提示:比较常用Bourne Again shell(bash)

查看Centos默认bash?

[root@db01 ~]# echo $SHELL
/bin/bash
[root@db01 ~]# echo shell
shell
[root@db01 ~]# grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash

修改创建用户默认配置文件路径

[root@db01 ~]# cat /etc/default/useradd 
# useradd defaults file
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
CREATE_MAIL_SPOOL=yes

Shell脚本的建立和执行

1.1 shell脚本的建立

在Linux系统中,shell脚本(bash shell程序)通常是在编辑器vi/vim)中编写,由Unix/Linux命令、bash shell命令、程序结构控制语句和注释等内容组成。

vi = 记事本

vim =编辑器emeditor、editplus notepad++

我们可以制作一个vi=vim的别名
[root@db01 ~]# alias vi='vim'  
[root@db01 ~]# vim /etc/profile
export alias 'vi=vim'
[root@db01 ~]# . /etc/profile

1.2 脚本开头(第一行)

一个规范的shell脚本在脚本第一行会指出由那个程序(解释器)来执行脚本中的内容,这一行内容在linux bash编程中一般为:

#!/bin/bash
or
#!/bin/sh <==255字符以内

其中开头的"#!"字符又称为幻数,在执行bash脚本的时候,内核会根据"#!"后的解释器来确定该用那个程序解释这个脚本中的内容。

注意:这一行必须在每个脚本顶端的第一行,如果不是第一行则为脚本注释行。

[root@web02 tmp]# cat 1.sh
#!/bin/bash
echo "123"
#!/bin/sh  <==代表注释
echo "456"

sh和bash的区别

早期的Bashsh稍有不同,它还包含了csh和ksh的特色,但大多数脚本都可以不加修改地在sh上运行

[root@web02 /]# ll /bin/sh 
lrwxrwxrwx. 1 root root 4 May  1 04:26 /bin/sh -> bash
[root@web02 /]# ll /bin/bash 
-rwxr-xr-x 1 root root 941720 Jul 24  2015 /bin/bash

企业面试题案例一:Centos Linux系统默认的shell是()

解答:bash

查看方法1:

[root@web02 ~]# echo $shell
bash
[root@web02 ~]# echo $SHELL
/bin/bash

查看方法2:

[root@web02 ~]# grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
提示:结尾的/bin/bash就是shell解释器

1.3 脚本注释

在shell脚本中,跟在(#)井号后面的内容表示注释,用来对脚本进行注释说明,注释部分不会被当做程序执行,仅仅给用户看,系统解析器是看不到,更不会执行。

特别提示:注释尽量不使用中文

1.4 Shell脚本的执行

当shell脚本运行时,它会先查找系统环境变量ENV,改变量指定了环境文件(通常是~./bashrc,~./bash_profile,/etc/bashrc,/etc/profile等)然后从该环境变量文件开始执行脚本,当读取了ENV的文件后,shell才会开始执行shell脚本中的内容

特殊技巧:设置crond任务时,最好把系统环境变量在定时脚本中重新定义,否则,一些系统环境变量不会被夹在。

Shell 脚本的执行通常可以采用以下几种方式:

1.bash script-name或sh script-name(推荐使用)
2.path/script-name或./script-name(当前路径下执行脚本)
###<==此项需要脚本有执行权限
3.source script-name 或. script-name #<==注意"."点号和后面字符之间有空格。
4.sh 

全路径执行如果不加命令全路径会没有权限

/server/scripts/abc.sh 权限不够
/bin/sh /server/scripts/abc.sh  可以执行

提示:

第三种方法通常是使用source或者”.”点号读入或加载指定的shell脚本文件(如san.sh),然后,依次执行指定shell脚本文件san.sh 中的所有语句。这些语句将作为当前父shell脚本运行。

source或者”.”点号命令的功能是在当前shell中执行source或者”.”点号加载并执行相关脚本文件中的命令以及语句,而不是产生一个字shell来执行命令文件中的命令。

脚本里面的内容是无法和外面的变量沟通,但是外面的变量在脚本里面是可以引用的。

如果想在脚本里面的变量引用到命令行需要使用source or .

Shell 变量类型

变量可以分为两类:环境变量(全局变量)和普通变量(局部变量)

环境变量也可称为全局变量,可以在创建他们的Shell及其派生出来的任意子进程shell中使用,环境变量又可分为自定义环境变量和Bash内置的环境变量

普通变量也可称为局部变量,只能在创建他们的Shell函数或Shell脚本中使用。普通变量一般是由开发者用户开发脚本程序时创建的。

环境变量

    环境变量一般用于定义Shell的运行环境,保证Shell命令的正确执行,Shell通过环境变量来确定登录用户、命令路径、终端类型、登录目录等,所有的环境变量都是系统全局变量,可用于所有子进程,这包括编辑器,Shell脚本和各类应用(crond任务必须比较特殊)
    环境变量可以在命令行中设置创建,但用户退出命令行时这些变量值就会丢失,因此,如果希望永久保存环境变量,可在用户家目录下的.bash_profile或.bashrc文件中或全局配置/etc/bashrc/或/etc/profile 文件或者/etc/profile.d中定义。将环境变量放入上述的文件中,每次用户登录时这些变量值都将被初始化一次
    有一些环境变,比如HOME、PATH、UID、USER等,在用户登陆之前就已经被/bin/login 程序设置好了。通常环境变量定义保存在用户家目录下的.bash_profile文件或者全局的配置文件/etc/profile中。

查看系统变量

env命令,也可以使用set (显示的没有env变量多)

[root@www ~]# env
HOSTNAME=www
TERM=linux
SHELL=/bin/bash
HISTSIZE=1000
SSH_CLIENT=125.34.74.61 51696 22
SSH_TTY=/dev/pts/0
USER=root
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=01;05;37;41:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arj=01;31:*.taz=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.zip=01;31:*.z=01;31:*.Z=01;31:*.dz=01;31:*.gz=01;31:*.lz=01;31:*.xz=01;31:*.bz2=01;31:*.tbz=01;31:*.tbz2=01;31:*.bz=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.rar=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.jpg=01;35:*.jpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.axv=01;35:*.anx=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=01;36:*.au=01;36:*.flac=01;36:*.mid=01;36:*.midi=01;36:*.mka=01;36:*.mp3=01;36:*.mpc=01;36:*.ogg=01;36:*.ra=01;36:*.wav=01;36:*.axa=01;36:*.oga=01;36:*.spx=01;36:*.xspf=01;36:
MAIL=/var/spool/mail/root
PATH=/application/mysql/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin
PWD=/root
LANG=en_US.UTF-8
HISTCONTROL=ignoredups
SHLVL=1
HOME=/root
LOGNAME=root
CVS_RSH=ssh
SSH_CONNECTION=125.34.74.61 51696 120.25.167.42 22
LESSOPEN=|/usr/bin/lesspipe.sh %s
G_BROKEN_FILENAMES=1
_=/bin/env

自定义环境变量

设置环境变量

如果想设置环境变量,就要给在变量赋值之后或设置变量时使用export命令。带-x选项的declare内置命令也可完成同样的功能。

格式:

1.export变量名=value
2.变量名=value;export 变量名
3.declare -x 变量名=value
提示:以上为三种设置环境变量的方法

例:
export NAME=oldboy
declare -x NAME=oldboy
NAME=oldboy;export NAME

让环境变量永久生效的常用设置文件及区别

1、用户的变量变量配置:

[root@www ~]# ls /root/.bashrc 
/root/.bashrc
[root@www ~]# ls /root/.bash_profile 
/root/.bash_profile
提示:用户的环境变量设置常见的为用户家目录下的.bashrc和.bash_profile

2、全局环境变量的配置

全局环境的配置文件常见的配置文件为

/etc/profile
/etc/bashrc
/etc/profile.d

需要登陆后初始化或显示加载内容可以把脚本文件放在/etc/profile.d下,设置可执行即可

3、生产环境 自定义JAVA环境配置实例

image_1b16q510c1k8t1r6keodblu6f32n.png-87.6kB

环境变量知识小结:

1、变量名通常要大写

2、变量可以在自身的shell以及子shell中使用。

3、通过export来定义环境变量

4、输出用$变量名,取消用unset变量名

5、书写定时任务要注意环境变量,最好在执行的shell脚本中重新定义。

6、如果系统永久生效可以放在用户环境变量文件或全局环境变量文件里。

1.1 普通变量

1.1.1 定义本地变量

本地变量在用户当前的Shell生存期的脚本中使用。例如,本地变量OLDBOY取值为bingbing,这个值在用户当前Shell生存期中有意义。如果在Shell中启动另一个进程或退出,本地变量值将无效

1. 普通变量定义

变量名=value    #<==赋值时不加引号
变量名='value'  #<==赋值时加单引号
变量名="value"  #<==赋值时加双引号

2.Shell中定义变量名及给变量内容赋值的要求

变量名一般是由字母、数字、下划线组成,可以字母或下划线开头

abc,abc123,abc_123

变量的内容可以使用单引号双引号引起来,也可不加引号,但是这三者是不同的。

3. 普通变量定义及输出的不同例子

[root@web02 ~]# a=1
[root@web02 ~]# b='2'
[root@web02 ~]# c="3"
[root@web02 ~]# echo "$a"
1
[root@web02 ~]# echo "$b"
2
[root@web02 ~]# echo "${c}"
3

提示:$变量名表示输出变量,可以用$c和${c}两种用法

小结:连续普通字符串内容赋值给变量,不管用什么引号或者不用引号,它的内容是什么,打印变量就输出什么

4.例子2

[root@db01 scripts]# a=192.168.1.2
[root@db01 scripts]# b='192.168.1.2'
[root@db01 scripts]# c="192.168.1.2"
[root@db01 scripts]# echo "a=$a"
a=192.168.1.2
[root@db01 scripts]# echo "b=$b"
b=192.168.1.2
[root@db01 scripts]# echo "c=${c}"
c=192.168.1.2
============================================
[root@db01 scripts]# a=192.168.1.2-$a
[root@db01 scripts]# b='192.168.1.2-$a'
[root@db01 scripts]# c="192.168.1.2-$a"
[root@db01 scripts]# echo "a=$a"
a=192.168.1.2-192.168.1.2
[root@db01 scripts]# echo "b=$b"
b=192.168.1.2-$a
[root@db01 scripts]# echo "c=${c}"
c=192.168.1.2-192.168.1.2-192.168.1.2

小结:数字内容变量定义可不加引号,其他没有特别要求的字符串等定义最好都加上双引号,确实真的需要原因输出的的就加单引号。

1.2 把一个命令的结果作为变量的定义方法

获取命令结果的变量内容写法常见的有两种:
变量名=`ls`         #<==命令用反引号引起来
变量名=$(ls)       #<==命令用$()括起来

自定义普通字符串变量

(1)内容是纯数字,简单连续字符(内容中不带任何空格)此时定义方式可以不加任何引号

a.OldboyAge=33
b.NETWORD=yes

(2)没特殊情况时,字符串一律用双引号定义,特别是多个字符串中间由空格时

a.NFS_MODULE="no load"
b.MyName="Good game"

(3)当变量里内容需要原样输出时,要用单引号'',这样的需求极少

a.HOST_NAME='OCALHOST'

提示:

1、变量名只能为字母、数字、下划线,只能以字母或下划线开头

2、规范的命令名写法要见名如意。

1)OldboyAge=1  #每个单词的首字母大写
2)oldboy_age=1 #单词之间用“_”
3)oldboyAgeSex=1 #驼峰语法:首个单词的首字母小写,其余单词首字母大写
4)OLDBOY=1 #单词全大写

1.3 变量定义的完整小结:

(1)普通变量内容的定义:

1.连续的数字或字符串,可以不加引号,例如a=123
2.变量内容很多,还希望解析变量,就加双引号,例如a="/etc/rc.local $USER",会对内容中的USER解析输出
3.希望原样输出就用单引号,例如:a='$USER'

(2)希望编译内容是命令得解析结果的定义:

1.反引号括起来,例如:a=`ls`
2.或者$()括起来,例如:a=$(ls)

(3)变量的输出方法:

使用$变量名输出变量内容,常用echo $变量名

1.4 变量定义的小结技巧:

1、注意命令变量定义前后的字符`` 例如"CMD=`ls`"
2、在变量名前加$,可以取得该变量的值,使用echo或printf命令可以显示变量的值,$A和${A}的写法不同,但功能是一样的。
3、用echo等命令输出变量的时候,也有单引号、双引号、反引号的形式。
4、$dbname_tname,若变量后面有其他字符连接的时候,就必须给变量加上大括号{}
例如:$dbname_tname就要改写成${dbname}_tname
5、养成所有字符串变量用双引号括起来使用的习惯,将会减少很多编程时遇到的问题。
有关shell变量定义及变量输出单引号、双引号不加引号的简要说明如下

951XY@]LD}]HGD5K8OL7}OC.png-20.2kB

1.5 特殊例子:awk调用shell变量引号例子

[root@db01 scripts]# ETT=123
[root@db01 scripts]# awk 'BEGIN {print "$ETT"}'
$ETT
[root@db01 scripts]# awk 'BEGIN {print '$ETT'}'
123
[root@db01 scripts]# awk 'BEGIN {print $ETT}'
一道实用linux运维问题的9种shell解答方法(http://oldboy.blog.51cto.com/2561410/760192)

Shell 特殊重要变量

1.1 Shell特殊位置变量

2.png-27.9kB

*和@的区别例子

1.$* 将命令行脚本所有参数视为单个字符串,等同于"$1$2$3",”$*“ 要用双引号
2.$@将命令行脚本每个参数视为单独的字符串,等同于"$1" "$2" "$3"这是将参数传递给其他程序的最佳方式,因为他会保留所有的内嵌在每个参数里的任何空白.
[root@web02 /]#for i in "$*";do echo $i;done
##在有双引号的情况下"$*"参数里引号内容当做一个参数输出了!
I am oldboy
[root@web02 /]#for i in "$@";do echo $i;done
##在有双引号的情况下,每个参数以独立的内容输出。
I am 
oldboy

其他:linux下set和eval的使用小案例精彩解答(特殊位置变量用法)

http://oldboy.blog.51cto.com/2561410/1175971

范例1:$n的实践例子

[root@web02 /]# cat p.sh 
#!/bin/bash
echo $1
[root@web02 /]# sh p.sh good         #传一个字符串参数
good
[root@web02 /]# sh p.sh good good    #传2个字符串参数,第二个不会接受,$1只显示第一个
good
[root@web02 /]# sh p.sh "good good"  #加引号括起来表示为一个字符串参数
good good

测试 26的英文字符

[root@db01 scripts]# cat q.sh   
echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} $12 $13 $14 $15
[root@db01 scripts]# sh q.sh {a..z}
a b c d e f g h i j k a2 a3 a4 a5

提示:脚本里面的就

1就是我们执行的第一个参数,例如/etc/init.d/iptables stop 其中stop相当于1

$0案例

[root@db01 scripts]# cat q.sh                  
echo $"Usage: $0 {start|stop}"
[root@db01 scripts]# /server/scripts/q.sh start
Usage: /server/scripts/q.sh {start|stop


$1 脚本传参的第一个参数,以此类推
$0 脚本的名字以及路径
$# 脚本传参的参数数量

例子:$?

$? 返回值

0 表示成功

 [root@db01 scripts]# cat q.sh 
#!/bin/sh
. /etc/init.d/functions
if [ $# -ne 1 ]
then
   echo $"Usage: $0 {start|stop}"
   exit 1
fi
rsync --daemon
if [ $? -eq 0 ]
then
   action "oldboy" /bin/true
fi

exit 1 脚本的返回值,此处的exit 1 可以随便定义。如果定义为1 $?返回的值就是1

return 1函数的返回值

Shell进程状态变量

$$ 获取当前shell脚本的进程号(PID)
$! 执行上一个指令的PID
$? 获取上一个指令的返回值(0为成功,非0为失败)
$_ 在此之前执行的命令或脚本的最后一个参数

提示:查找知道方法:man bash,然后搜索Special Parameters.

范例2:应用案例:当系统中只能有某个脚本同时只能运行一个进程的时候。

[root@oldboy day2]# cat pid.sh 
#!/bin/sh
pidpath=/tmp/a.pid
if [ -f "$pidpath" ] 
  then 
      kill -USR2 `cat $pidpath` >/dev/null 2>&1
      rm -f $pidpath
fi
echo $$ >$pidpath
sleep 300

bash内置命令(没有路径(二进制文件))

alias
break
cd
continue
declare
echo
eval
exec
exit
export
help
history
jobs
kill
let
local
logout
printf
pwd
read
readonly
return
set
shift
times
trap
typeset
ulimit
umask
unalias
unset

常用操作如下表:man bash找本节资料“Parameter Expansion”

${#string}                         返回$string的长度
${string:position}                 在$string中,从位置$position之后开始提取子串
${string:position:length}          在$string中,从位置$position之后开始提取长度为$length的子串
${string#substring}                从变量$string开头开始删除最短匹配$substring子串
${string##substring }              从变量$string开头开始删除最长匹配$substring子串
${string%substring}                从变量$string结尾开始删除最短匹配$substring子串
${string%%substring}               从变量$string结尾开始删除最长匹配$substring子串
${parameter/pattern/string}        使用string,来代替第一个匹配的pattern
${parameter/#pattern/string}       从开头匹配string变量中的pattern,使用string来替换匹配的pettern
${parameter/%patter/string}        从结尾开始匹配string变量中的pattern,就用string来替换匹配pattern
${parameter//pattern/string}       使用string,来代替所有匹配的pattern
更多资料man bansh 查找“Parameter Expansion”

获取变量字符串的长度

[root@db01 ~]# OLDBOY="I am oldboy"
[root@db01 ~]# echo $OLDBOY
I am oldboy
[root@db01 ~]# echo $OLDBOY|wc -L
11
[root@db01 ~]# echo ${#OLDBOY}
11
[root@db01 ~]# expr length "$OLDBOY"
11

截取OLDBOY变量字符串从第2个字符之后开始取,默认取后面字符的全部,第二个字符不包含在内。也可以理解为删除前面多少个字符。

[root@web02 /]# OLDBOY="I am oldboy linux,welcome to our training."
[root@web02 /]# echo $OLDBOY
I am oldboy linux,welcome to our training.
[root@web02 /]# echo ${OLDBOY:2}
am oldboy linux,welcome to our training.

截取OLDBOY变量字符串从第二个字符之后开始取,取2个字符

[root@web02 /]# echo ${OLDBOY:2:2}
am
提示:类似于cut -c参数;
[root@web02 /]# echo ${OLDBOY}|cut -c 1-4
I am
[root@web02 /]# echo ${OLDBOY}|cut -c 3-4
am

从变量$OLDBOY开头删除最短匹配"a*C"子串

[root@web02 /]# OLDBOY=abcABC123ABCabc
[root@web02 /]# echo ${OLDBOY#A*c}
abcABC123ABCabc
[root@web02 /]# echo ${OLDBOY#a*c}
ABC123ABCabc
[root@web02 /]# echo ${OLDBOY#a*C}
123ABCabc
[root@web02 /]# echo ${OLDBOY##a*c}



[root@db01 ~]# OLDBOY="I am oldboy"
[root@db01 ~]# echo ${OLDBOY/oldboy/oldgirl}
I am oldgirl
[root@db01 ~]# OLDBOY="I am oldboy oldboy"  
[root@db01 ~]# echo ${OLDBOY/oldboy/oldgirl}
I am oldgirl oldboy

小结:

#是开头删除匹配最短

##是开头删除匹配最长

%是结尾删除匹配最短

%%是结尾删除匹配最长

生产案例:

httpd=${HTTPD-/usr/sbin/httpd}
prog=httpd
pidfile=${PIDFILE-/var/run/httpd/httpd.pid}
lockfile=${LOCKFILE-/var/lock/subsys/httpd}
RETVAL=0
STOP_TIMEOUT=${STOP_TIMEOUT-10}

企业场景例子:尽量不要使用rm

[root@MySQL test]# cat del.sh
path=/server/backup
find ${path:=/tmp/} -name "*.tar.gz" -type f |xargs rm -f
===================
 path=/server/backup
find ${path:=/tmp/} -name "*.tar.gz" -type f |xargs rm -f
[root@MySQL test]# cat del.sh
path=/server/backup
find ${path:=/tmp/} -name "*.tar.gz" -type f |xargs rm -f
[root@MySQL test]# sh -x del.sh
+ path=/server/backup
+ find /server/backup -name '*.tar.gz' -type f
+ xargs rm -f
[root@MySQL test]# sed -i '1d' del.sh
[root@MySQL test]# cat del.sh
find ${path:=/tmp/} -name "*.tar.gz" -type f |xargs rm -f
[root@MySQL test]# sh -x del.sh
+ find /tmp -name '*.tar.gz' -type f
+ xargs rm -f
#rm -fr ${path:=/tmp/}

扩展:其他变量的替换

变量替换表:了解,man bash查到资料Parameter Expansion

image_1b16rb59912t71vbn1nvq9cl8d549.png-237.9kB

image_1b16rbe73147s102t1feo34er9u4m.png-34.7kB

image_1b16rbmn97nq1gbk9mbojj1igm53.png-74.7kB

变量的数值(整数)计算

变量的数值计算常见的有如下几个命令:

(())、let、expr、bc(小数)、$[],其他都是整数

如果要执行简单的整数运算,只需将特定的算术表达式用"$(("和"))" 括起来即可。
shell的算术运算符号常置于"$(("......"))"的语法中。这一语法如同双引号的功能

image_1b16reaf114d22b0rqh1vb11ilq5g.png-211.1kB

1)(())用法:(此方法很常用)**

范例:shell的算术运算实例如下:

[root@db01 ~]# ((a=1+2**3-4%3))
[root@db01 ~]# echo $a
8
[root@db01 ~]# ((a=1+2**3-4%3))
[root@db01 ~]# echo $a
8
[root@db01 ~]# echo $((1+2**3-4%3))
8

记忆方法:++,--

变量a在前,表达式的值为a,然后a自增或自减,变量a在符号后,表达式值自增或自减,然后a值自增或自减

[root@db01 ~]# a=$((100*(100+1)/2)) 
[root@db01 ~]# echo $a
5050

范例6:这是一个实践考试题,内容如下:

把a,b两个变量通过命令行脚本传参的方式实现上面混合运算脚本的功能

第一种方法:

#!/bin/bash
a=6
b=2
echo "a-b =$(( $a - $b ))"
echo "a+b =$(( $a + $b ))"
echo "a*b =$(( $a * $b ))"
echo "a/b =$(( $a / $b ))"
echo "a**b =$(( $a ** $b ))"
echo "a%b =$(( $a % $b ))"

第二种方法:

[root@web02 ~]# cat abc.sh
#!/bin/bash
a=$1
b=$2
echo "a-b =$(( $a - $b ))"
echo "a+b =$(( $a + $b ))"
echo "a*b =$(( $a * $b ))"
echo "a/b =$(( $a / $b ))"
echo "a**b =$(( $a ** $b ))"
echo "a%b =$(( $a % $b ))"

2)let命令的用法(整数)

格式:

let 赋值表达式

【注】let赋值表达式功能等同于:((赋值表达式))

范例1:给自变量i加8

[root@db01 scripts]# i=2    
[root@db01 scripts]# let i=i+8
[root@db01 scripts]# echo $i  
10 

3)expr (evaluate(求值)expressions(表达式))命令的用法:

    expr命令一般用于整数值,但也可用于字符串,用来求表达式变量的值,同时expr也是一个手工命令计算器

1.计算

语法:expr Expression

[root@web02 /]# expr 2 + 2
4
[root@web02 /]# expr 2 - 2
0
[root@web02 /]# expr 2 * 2
expr: syntax error  语法错误
[root@web02 /]# expr 2 \* 2
4
[root@web02 /]# expr 3 / 2
1
[root@web02 /]# expr 3 % 2
1

另一种玩法

[root@db01 scripts]# i=0
[root@db01 scripts]# i=`expr $i + 1`
[root@db01 scripts]# echo $i
1 

expr $[$a+$b]表达式形式,其中$a $b 可为整数值

[root@web02 /]# expr $[2+3]
5
[root@web02 /]# expr $[2*3]
6
[root@web02 /]# expr $[2**3]        2的2次方*3
8
[root@web02 /]# expr $[2/3]
0
[root@web02 /]# expr $[2%3]
2

四种运算方法:

1.(())
2.let
3.expr
4.[]
整数

判断一个文件的扩展名是不是pub(发送公钥的命令就是使用此参数)

#!/bin/sh
if expr "$1" : ".*\.pub" &>/dev/null
  then 
   echo "you are using $1"
else
   echo "pls use *.pub file"
fi 
[root@web02 ~]# sh aaa.sh oldboy
pls use *.pub file
[root@web02 ~]# sh aaa.sh oldboy.pub
you are using oldboy.pub

判断一个输入是不是数字

 #!/bin/sh
while true
do
  read  -p "Pls input:" a
  expr $a + 0 >/dev/null 2>&1
  [ $? -eq 0 ] &&echo int||echo chars
done

如果判断是不是数字,就执行错误shars

[root@db01 scripts]# cat b.sh 
#!/bin/sh
expr $1 + 1 >/dev/null 2>&1
[ $? -eq 0 ] &&echo int||echo chars
[root@db01 scripts]# sh b.sh  1
int
[root@db01 scripts]# sh b.sh  1a
chars
[root@db01 scripts]# sh b.sh  100
int
[root@db01 scripts]# sh b.sh  100abc
chars

expr match 整数判断

[[ `expr match "$a" "[0-9][0-9]*$"` == 0 ]] && {
        echo "the first is not a num"
        exit 3
}

计算变量长度

[root@db01 scripts]# a="oldboy"
[root@db01 scripts]# expr length "$a"
6

expr功能

1.整数计算

2.判断扩展名

3.判断输入是否为整数

4.计算变量的长度

[root@db01 scripts]# bc
bc 1.06.95
Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc.
This is free software with ABSOLUTELY NO WARRANTY.
For details type `warranty'. 
1+1
2
1+3
4
6*8
48

另一种使用bc的方式

[root@db01 scripts]# echo 1+2|bc
3
[root@db01 scripts]# echo 8-2|bc
6

inux下的bc命令可以设置结果的位数,通过scale.

[root@db01 scripts]# echo "scale=3;5.23 / 3.13"|bc
1.670
[root@db01 scripts]# echo "scale=2;5.23 / 3.13"|bc 
1.67
比如:
$ echo "scale=4; 1.2323293128 / 1.1" | bc -l
1.1202

bc命令简单的算法

[root@web02 ~]# i=2
[root@web02 ~]# i=`echo $i+1|bc`
[root@web02 ~]# echo $i
3

可以做加法计算
[root@web02 ~]# echo 3.5+5
3.5+5
[root@web02 ~]# echo 3.5+5|bc
8.5

减法计算
[root@web02 ~]# echo 3.5-5|bc
-1.5

乘法计算
[root@web02 ~]# echo 3.5*5|bc
17.5

保留位数(bc的用处不大)
[root@web02 ~]# echo "scale=2; 3.5*5.1"|bc
17.85
[root@web02 ~]# echo "scale=2; 3*5"|bc
15
[root@web02 ~]# echo "scale=1; 3*5"|bc
15
提示:bc是特有的小数计算

awk也可以进行小数计算
[root@web02 ~]# echo "5.5 5.6" |awk '{print ($2-$1)}'
0.1
[root@web02 ~]# echo "5.5 5.5" |awk '{print ($2+$1)}'
11

范例:通过一条命令计算输出1+2+3+...+10的表达式,并计算出结果,使用bc计算

输出内容如:1+2+3+4+5+6+7+8+9+10=55

第一种方法:

[root@web02 ~]# seq -s "+" " "10
1+2+3+4+5+6+7+8+9+10
[root@web02 ~]# echo `seq -s "+" " "10`=`seq -s "+" " "10|bc`
1+2+3+4+5+6+7+8+9+10=55

第二种方法:

[root@web02 ~]# echo {1..10}|tr " " "+"
1+2+3+4+5+6+7+8+9+10
[root@web02 ~]# echo `echo {1..10}|tr " " "+"`=`echo {1..10}|tr " " "+"|bc`
1+2+3+4+5+6+7+8+9+10=55

更多方法:因计算不是重点,所以我们不重点研究。

image_1b16rugc213ko1lp712j91c5s1ha95t.png-86.5kB

特点:bc的独有特点是支持小数运算,当然也可以整数运算。

typeset命令的用法

使用整数变量进行计算

例如:

[root@web02 ~]# typeset -i A=1 B=3
[root@web02 ~]# A=A+B
[root@web02 ~]# echo $A
4

小结:

shell的数值运算方法:

expr、(())、let、bc、$[]、awk typeset

「点点赞赏,手留余香」

    还没有人赞赏,快来当第一个赞赏的人吧!
0 条回复 A 作者 M 管理员
    所有的伟大,都源于一个勇敢的开始!
欢迎您,新朋友,感谢参与互动!欢迎您 {{author}},您在本站有{{commentsCount}}条评论