老男孩shell教程(1-5章节)

关于查看系统变量命令

set: 输出所有的变量,包括全局变量和局部变量

env:只显示全局变量

declare:输出所有的变量、函数、整数和已经导出(export)的变量

删除环境变量

unset 变量名

关于设置(全局)环境变量的三种方法

export 变量名=value

变量名=value ; export 变量名

declare -x 变量名=value

全局环境变量配置

/etc/profile/

/etc/bashrc/  (推荐在此文件优先设置)

/etc/profile.d/  (登陆后初始化或显示加载内容,文件无需执行权限)

普通环境变量三种定义方法

变量名=value 

变量名='value'

变量名="value"

shell中的特殊位置参数变量,请见下表

关于特殊位置参数实战

使用条件表达式判断语句

# cat test_variable.sh
#!/bin/bash

#create by wutf
#Creation time 2018-10-18

[ $# -ne 2 ] && {
    echo "must two args"
    exit 1
}
echo "this is a test!"

当然脚本中的核心代码,也可以写成:

[ $# -ne 2 ] && {
    echo "must two args"
    exit 1
} || echo "this is a test!"

执行脚本:

[root@wtf tmp]# sh test_variable.sh wtf
must two args
[root@wtf tmp]# sh test_variable.sh wtf didi
this is a test!
[root@wtf tmp]# sh test_variable.sh
must two args

使用 if 判断语句

#!/bin/bash

#create by wutf
#Creation time 2018-10-18

if [ $# -ne 2 ]
    then
        echo "USAGE:/bin/sh $0 arg1 arg2"
        exit 2
    else
        echo "this is a test!"
fi

执行脚本:

# sh test_variable.sh
USAGE:/bin/sh test_variable.sh arg1 arg2
# echo $?
2
# sh test_variable.sh wtf
USAGE:/bin/sh test_variable.sh arg1 arg2
# sh test_variable.sh wtf didi
this is a test!
# echo $?
0

关于 $@ 与 $* 的异同点

  • 相同点:不带引号时,即 $@ $* ,表示传入脚本中参数的个数
  • 不同点:添加引号,即 "$@" "$*" ,参考下面代码实例

设置三个参数变量:

# set -- "I am" datagrand yunwei ## 通过 set 设置三个字符串参数,"--" 表示清除所有的参数变量,重新设置后面的参数变量
# echo $1
I am
# echo $2
datagrand
# echo $3
yunwei

使用 for 循环测试:

# for i in "$*";do echo $i;done
I am datagrand yunwei
# for i in "$@";do echo $i;done
I am
datagrand
yunwei

另外注意⚠️一个命令:shift (将位置参数移位,左移),如:

# echo $1
I am
# shift
# echo $1
datagrand
# echo $2
yunwei
# echo $3

bash shell 内置变量命令

常用的内部命令:

echo eval exec export read shift

echo 在屏幕上输出信息

命令格式:echo args # 可以是字符串和变量的组合

功能说明:将echo命令后面args指定的字符串及变量等显示到标准输出。

常见参数如下:

实战--echo参数

# echo wutf
wutf
# echo -n wutf
wutf[root@wtf ~]#
# echo "wutf\tdatagrand\tdata\tgrand"
wutf\tdatagrand\tdata\tgrand
# echo -e "wutf\tdatagrand\tdata\tgrand"
wutf	datagrand	data	grand
# echo -e "wutf\tdatagrand\ndata\tgrand"  ## 等价于# printf "wutf\tdatagrand\ndata\tgrand\n"
wutf	datagrand
data	grand

说明⚠️:printf 功能更强大,当需要特殊负载的格式时才考虑使用printf。

eval

命令格式:eval cmd ==>cmd包含变量等命令

功能:当shell程序执行到eval语句时,shell读入参数cmd,并将它们组合成一个新的命令,然后去执行。简单点说,

就是eval会对后面的cmd进行两遍扫描,如果第一遍扫描后,cmd是个普通的命令,则执行此命令,如果cmd中含

有变量,则第一遍扫描先确认变量的值,然后进行第二遍扫描,得出结果,例如:

# set -- arg1 arg2       ==>通过set设置两个参数
# echo $#             ==>$#表示传参的个数
2
# echo \$$#            ==>由于$#为2,所以此命令就变为echo $2 ,但此时并未输出$2的值,而是输出了$2,这也就是上述提到的提一次扫描,将$#替换为$2                                                                 
$2
# eval "echo \$$#"      ==>eval进行第2次扫描,直接输出echo $2的值arg2
arg2

exec

命令格式:exec 命令参数

功能:exec命令能够在不创建新的子进程的前提下,转去执行指定的命令,当指定的命令执行完毕后,该进程也就

终止了,如果是远程连接的会话,则执行完命令后,该会话直接退出。

如下:

[root@wtf ~]# exec date
2018年 10月 18日 星期四 14:32:19 CST
Connection to 192.168.246.171 closed.
➜  ~

另外,当使用exec打开文件后,read命令每次都会将文件指针移动到文件的下一行进行读取,直至文件末尾,

利用这个可以实现处理文件内容。

例如:

# seq 5 > /tmp/seq.txt

[root@wtf tmp]# cat test_seq.sh
#!/bin/bash

exec < /tmp/seq.txt
while read line
do
    echo $line
done
echo "ok"

执行 test_seq.sh ,结果如下:

# sh test_seq.sh
1
2
3
4
5
ok

read

命令格式:read 变量名表

功能:从标准输入读取字符串等信息,传给shell程序内部定义的变量。

shift

用shift将位置参数移位(左移),将位置参数$1、$2等进行左移,即如果位置参数是$3、$2、$1,

那么执行一次shift后,$3变为$2,$2变为$1,$1就消失了。

exit

shell程序,当然exit也可以选择执行的数字作为返回值。

shell变量子串知识

说明⚠️:

  • 上述ID为11-14中表达式的冒号可以省略,如果省略了其中的冒号,则将每个定义中的“为空或未赋值”部分改为“未赋值”。
  • 为了方便理解,这里对${#parameter##word}举例说明一下:
${#parameter%%  a*c} :这里的a*c表示匹配的字符串,*表示匹配所有,a*c表示匹配开头为a、中间为任意多字符,结尾为c的字符串。

有关上述匹配删除的小结,总结如下:

有关上述替换匹配的小结,总结如下:

变量的数值计算实践

算术运算符

这里重点说一下 ++ 和 —— ,因为有时候大家会对此有一定的误解,看如下实例:

[root@www ~]# a=10           ==>定义变量a
[root@www ~]# echo $((a++))      ==>如果a在运算符++或--的前面,那么输出整个表达式时,会输出a的值, 此前定义的变量a为10,所以此处的值为10.
10
[root@www ~]# echo $a         ==>执行上述表达式后,因为有a++,因此a会自增1,所以输出的值为11
11
[root@www ~]# a=11           ==>定义变量a
[root@www ~]# echo $((a--))     ==>如果a在运算符++或--的前面,那么输出整个表达式时,会输出a的值,前定义的a为11,所以此处的值为11.
11
[root@www ~]# echo $a         ==>执行上述表达式后,因为有a--,因此a会自减1,所以输出的值为10
10
[root@www ~]# a=10
[root@www ~]# echo $((--a))      ==>如果a在运算符++或--的后面,那么输出整个表达式时,先进行自增或自减计算,因为a为10,  且要自减,所以表达式的值为9.
9
[root@www ~]# echo $a         ==>执行上述表达式后,a自减1,所以表达式的值为9.
9
[root@www ~]# echo $((++a))     ==>如果a在运算符++或--的后面,那么输出整个表达式时,先进行自增或自减计算,因为a为9,且要自增1,所以表达式的值为10
10
[root@www ~]# echo $a         ==>执行上述表达式后,a自增1,所以表达式的值为10
10

总结⚠️:

执行echo $((a++))和echo $((a--))命令输出整个表达式时,输出的值为a的值,表达式执行完毕后,会对a进行++、--的运算,而执行

echo $((++a))和echo $(--a)命令输出整个表达式时,会先对a进行++、--的运算,然后再输出表达式的值,即为a运算后的值。

记忆口诀⚠️:

变量a在运算符之前,输出表达式的值为a,然后a自增或自减;

变量a在运算符之后,输出的表达式会先进行自增或自减,表达式的值就是自增或自减后a的值。

常见的算术运算命令:

双小括号"(())"数值运算命令

双小括号"(())"数值运算的基础语法

双小括号"(())"的作用是进行数值运算与数值比较,效率很高,用法灵活,是企业场景运维人员经常采用的运算操作符。

操作方法见下表:

实战--双小括号

基础运算
[root@wtf tmp]# echo $((1+1))
2
[root@wtf tmp]# echo $((8-3))
5
[root@wtf tmp]# echo $((2-3))
-1
[root@wtf tmp]# ((i=4)) 或 i=4
[root@wtf tmp]# ((i=i*3))  ## 获取 i 值,然后计算 i*3 ,再赋值给变量 i
[root@wtf tmp]# echo $i
12
综合算术运算
[root@wtf tmp]# ((a=1+2**4-4%3))
[root@wtf tmp]# echo $a
16
[root@wtf tmp]# ((a=1+2**4-4%3))
[root@wtf tmp]# echo $a
16
[root@wtf tmp]# b=$((1+2**4-4%3))
[root@wtf tmp]# echo $b
16
特殊运算符号的运算
[root@wtf tmp]# a=7
[root@wtf tmp]# echo $((a=a+1))
8
[root@wtf tmp]# echo $((a+=1))
9
[root@wtf tmp]# echo $((a**2))
81
利用 “(())” 双小括号进行判断
[root@wtf tmp]# echo $((3<5))  ## 1 表示真
1
[root@wtf tmp]# echo $((3<1))  ## 0 表示假
0
通过 “(())” 运算后赋值给变量
[root@wtf tmp]# myvar=100
[root@wtf tmp]# echo $((myvar+1))
101
或者:
[root@wtf tmp]# myvar=100
[root@wtf tmp]# myvar=$((myvar+1))
[root@wtf tmp]# echo $myvar
101

说明⚠️:

在 “(())” 中使用变量时可以去掉变量前的 $ 符号。

双小括号 “(())” 在 Shell 脚本中的运用
[root@wtf tmp]# cat shuang_shell.sh
#!/bin/bash

## 这里可以使用位置参数,使脚本具有更好的灵活性,如:
#a=$1
#b=$2
##那么执行脚本时,要使用位置参数,如:
#sh shuang_shell.sh 3 4

a=6 
b=2

echo "a-b=$((a-b))"  ## 在 “(())” 中使用变量时可以去掉变量前的 $ 符号。
echo "a+b=$(($a+$b))"

[root@wtf tmp]# sh shuang_shell.sh
a-b=4
a+b=8

实战--以上介绍的知识点

具体代码如下:

#!/bin/bash
#add,subtract,multiply and divide by oldboy

print_usage(){
    printf $"USAGE:$0 NUM1 {+|-|*|/} NUM2\n"
    exit 1
}

if [ $# -ne 3 ];then
    print_usage
fi

firstnum=$1
secondnum=$3
operators=$2

if [ -n "$(echo $firstnum|sed 's#[0-9]##g')" ];then
    print_usage
fi

if [ "${operators}" != "+" ] && [ "${operators}" != "-" ] && [ "${operators}" != "*" ] && [ "${operators}" != "/" ];then
    print_usage
    exit 2
fi

if [ -n "$(echo $secondnum|sed 's#[0-9]##g')" ];then
    print_usage
fi

echo "${firstnum}${operators}${secondnum}=$((${firstnum}${operators}${secondnum}))"

代码执行结果如下:

[root@wtf tmp]# sh jisuanqi_v2.sh 1 + 2
1+2=3
[root@wtf tmp]# sh jisuanqi_v2.sh 3 \* 2  ## * 要转义
3*2=6
[root@wtf tmp]# sh jisuanqi_v2.sh 4 / 2
4/2=2
[root@wtf tmp]# sh jisuanqi_v2.sh wutf /  2
USAGE:jisuanqi_v2.sh NUM1 {+|-|*|/} NUM2
[root@wtf tmp]# sh jisuanqi_v2.sh 4 / wutf
USAGE:jisuanqi_v2.sh NUM1 {+|-|*|/} NUM2

let运算命令的用法

let运算命令的语法格式:let 赋值表达式

let赋值表达式的功能等同于“((赋值表达式))”

let赋值:举例:let i=i+2 ==>等同于((i=i+2)),后者的效率更高!

expr命令的用法

expr命令的基本用法:

expr既可以用于整数运算,也可以用于相关字符串长度、匹配等的运算处理。

expr 用于计算

语法:expr Expression ==>expression中可包含变量

[root@wtf tmp]# expr 1 + 1
2
[root@wtf tmp]# expr 2 \* 3
6

说明⚠️:

在使用expr时,要注意以下2点

  • 运算符及用于计算的数字左右都至少有一个空格,否则会报错。
  • 使用乘号时,必须用反斜线进行转义。
expr 配合变量计算

expr 在 shell 中可配合变量进行计算,但需要用反引号或 $() 将计算表达式括起来,如:

[root@wtf tmp]# i=5
[root@wtf tmp]# i=$(expr $i + 5)
[root@wtf tmp]# echo $i
10
判断变量或字符串是否为整数

原理:

利用以 expr 做计算时变量或字符串必须是整数的规则,把一个变量或字符串和一个已知的整数(非0)相加,看命令返回的值是否为0。

如果是0,就认为做加法的变量或字符串为整数,否则就不是整数。

[root@wtf tmp]# i=7
[root@wtf tmp]# expr $i + 2 &> /dev/null  ## &> /dev/null表示不保留任何输出
[root@wtf tmp]# echo $?  ## 表示返回值
0
[root@wtf tmp]# expr $i + 2
9
[root@wtf tmp]# unset i
[root@wtf tmp]# i=wutf
[root@wtf tmp]# expr $i + 2 &> /dev/null
[root@wtf tmp]# echo $?
2
[root@wtf tmp]# expr $i + 2
expr: 非整数参数
通过传参判断输出的内容是否为整数
# cat expr_test.sh
#!/bin/bash

expr $1 + 1 > /dev/null
[ $? -eq 0 ] && echo int || echo chars

执行上面的脚本,结果如下:

[root@wtf tmp]# sh expr_test.sh 1
int
[root@wtf tmp]# sh expr_test.sh wutf
expr: 非整数参数
chars

bc命令的用法

bc是Linux下的计算器,当然除了作为计算器使用,还可以作为命令行计算工具使用。

使用方法如下:

[root@wtf ~]# 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
3*3
9
[root@wtf ~]# echo 2+3|bc
5
[root@wtf ~]# echo "scale=2;9/2" | bc   ==>使用scale=2保留2位小数
4.50
[root@wtf ~]# echo "scale=2;355/113" | bc 
3.14

awk实现计算

利用awk运算的效果也很好,适合小数和整数,尤其是小数,运算很精确。

示例如下:

[root@wtf ~]# echo "5 6" | awk '{print ($1+$2)}'      ==>$1为第1个数字,$2为第2个数字,用空格分开 ,注意awk '{ }'的单引号
11
[root@wtf ~]# echo "5.5 6.6" | awk '{print ($1+$2)}'
12.1

declare(同typeset)命令的语法

declare与typeset命令是bash的内置命令,二者命令的语法相同,用来声明shell变量,设置变量的属性。

常用命令参数:

  • -r:设置变量为只读
  • -i:设置变量为整数
  • -a:设置变量为数组array
  • -f:如果后面没有参数的话,会列出之前脚本定义的所有函数,如果有参数的话,列出以参数命名的函数
  • -x:设置变量在脚本外也可以使用

简单使用如下:

[root@wtf ~]# declare -i A=1 B=2
[root@wtf ~]# A=A+B
[root@wtf ~]# echo $A
3

$[ ]符号的运算示例

[root@wtf ~]# echo $[1+2] 
3
[root@wtf ~]# echo $[1*2]
2

基于shell变量输入read命令的运算实践

shell脚本除了可以直接赋值或脚本传参外,还可以使用read命令从标准输入中获得,read为bash的

内置命令,而已通过help read查看帮助。

语法格式:read [参数] [变量名]

常用参数:

-p(prompt):设置提示信息

-t(timeout):设置输入等待时间,单位默认为秒。

实例如下:

# read -t 7 -p "Please input a number: " number
Please input a number: [root@wtf ~]#

写在最后

喜欢读技术书籍,喜欢做读书笔记,以上为本人在读《跟老男孩学Linux运维之shell编程实战》这本书时的笔记,如有任何版权问题,请联系留言。