shell本身就是一门解释型、弱类型、动态语言,与python相对应,Python属于解释型、强类型、动态语言,我们平时登录成功一个用户后进入的就是bash解释器的交互式环境,我们敲的命令其实都属于shell这门语言的语法

如何区别强类型与弱类型语言

shell属于弱类型语言

  • 比如linux中的shell中定义一个变量,是随着调用方式的不同,数据类型可随意切换的那种,即shell对数据类型的概念没有那么强的要求。
echo "1+abc"
1+abc

python属于强类型语言

  • 强类型语言: 数据类型不可以被忽略的语言
    即变量的数据类型一旦被定义,那就不会再改变,除非进行强转。
python
Python 2.7.5 (default, Oct 14 2020, 14:45:30) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-44)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print(1+"abc")
Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'int' and 'str'

shell语言与python语言的差别

Shell 脚本的优势在于处理偏操作系统底层的业务,例如,Linux 内部的很多应用(有的是应用的一部分)都是使用 Shell 脚本开发的,因为有 1000 多个 Linux 系统命令为它作支撑,特别是 Linux 正则表达式以及三剑客 grep、awk、sed等命令。
对于一些常见的系统脚本,使用 Shell开发会更简单、更快速,例如,让软件一键自动化安装、优化,监控报警脚本,软件启动脚本,日志分析脚本等,虽然 Python也能做到这些,但是考虑到掌握难度、开发效率、开发习惯等因素,它们可能就不如 Shell 脚本流行以及有优势了。对于一些常见的业务应用,使用Shell 更符合 Linux 运维简单、易用、高效的三大原则。

Python 是近几年非常流行的语言,它不但可以用于脚本程序开发,也可以实现 Web程序开发(知乎、豆瓣、YouTube、Instagram 都是用Python 开发),甚至还可以实现软件的开发(大名鼎鼎的OpenStack、SaltStack 都是 Python 语言开发)、游戏开发、大数据开发、移动端开发。

现在越来越多的公司要求运维人员会 Python 自动化开发,Python 也成了运维人员必备的技能,每一个运维人员在熟悉了 Shell之后,都应该再学习 Python 语言。

Python 语言的优势在于开发复杂的运维软件、Web 页面的管理工具和 Web 业务的开发(例如 CMDB自动化运维平台、跳板机、批量管理软件 SaltStack、云计算OpenStack 软件)等。

运行shell脚本程序的几种方式

[root@m01 ~]# vim /a/b/a.sh
#!/bin/bash
echo "hello world"
方式一:绝对路径,此时采用的是文件头指定的解释器来解释执行文件内代码
# 权限:
# 1、对沿途文件夹有x权限
# 2、对目标文件有r和x权限

# 例
[root@m01 ~]# ll -d /a
d--------x. 3 root root 15 11月 15 11:05 /a
[root@m01 ~]# ll -d /a/b
d--------x. 2 root root 18 11月 15 11:06 /a/b
[root@m01 ~]# ll /a/b/a.sh
-rw-r--r-x. 1 root root 10 11月 15 11:06 /a/b/a.sh
[root@m01 ~]# su - nana
Last login: Tue Jun 15 17:00:30 CST 2021 on pts/0
[nana@m01 ~]$ /a/b/a.sh
hello world
方式二:相对路径,需要加./作为前缀,此时采用的仍是文件头指定的解释器来解释执行文件内代码
# 权限:
# 1、对沿途文件夹有x权限
# 2、对目标文件有r和x权限

# 例
[root@m01 ~]# ll -d /a
d--------x. 3 root root 15 11月 15 11:05 /a
[root@m01 ~]# ll -d /a/b
d--------x. 2 root root 18 11月 15 11:06 /a/b
[root@m01 ~]# ll /a/b/a.sh
-rw-r--r-x. 1 root root 10 11月 15 11:06 /a/b/a.sh
[root@m01 ~]# su - nana
Last login: Tue Jun 15 17:06:46 CST 2021 on pts/0
[nana@m01 ~]$ /a/b/a.sh				# 绝对路径的方式
hello world
[nana@m01 ~]$ cd /a
[nana@m01 a]$ ./b/a.sh				# 相对路径的方式
hello world
方式三:解释器+文件路径(绝对路径或相对路径都可以),此时采用的是我们自己指定的解释器来解释执行文件内代码
# 权限:
# 1、对沿途文件夹有x权限
# 2、对目标文件有r权限即可
因为我们执行的是解释器,当前用户对解释器有执行权限就可以了,这个权限默认就有,而解释器需要读文件内容来执行,所以需要对目标文件有r权限

# 例
[root@m01 ~]# chmod -R o=x /a
[root@m01 ~]# chmod o=r /a/b/a.sh
[root@m01 ~]# su - nana
Last login: Tue Jun 15 17:23:20 CST 2021 on pts/0
[nana@m01 ~]$ cd /a
[nana@m01 a]$ bash b/a.sh
hello world
方式四:上述三种方式都是在子shell进程中执行程序,而方式四则是在当前shell进程中执行
# 权限:
# 1、对沿途文件夹有x权限
# 2、对目标文件有r权限即可

上述三种方式都是在当前shell环境下开启了一个新的shell解释器环境/子shell来执行程序,
脚本程序在子shell中运行完毕后,子shell环境随即关闭,然后返回到父级shell即当前shell环境中,
如果就想在当前shell环境中执行,需要这么做

# 例
[root@m01 ~]# chmod -R o=x /a
[root@m01 ~]# chmod o=r /a/b/a.sh
[root@m01 ~]# su - nana
Last login: Tue Jun 15 17:26:48 CST 2021 on pts/0
[nana@m01 ~]$ . /a/b/a.sh		# . 后跟空格,然后再跟绝对路径
hello world
[nana@m01 ~]$ cd /a/b/
[nana@m01 b]$ . a.sh		 # . 后跟空格,然后再跟相对路径
hello world
[nana@m01 b]$ source a.sh	 # 跟上述方式一样
hello world

在当前shell解释器进程中执行脚本与在子shell进程中执行脚本的区别在于作用域

调试shell程序

vim login.sh
#!/bin/bash

read -p "name:" name
read -p "password:" pwd

if [[ $name == "nana" && $pwd == "123" ]];then
        echo "登陆成功"
else
        echo "账号或密码错误"
fi
调式方式1:以调试的方式运行
bash -vx login.sh 			 # 不加-v选项,只会显示程序中运行的代码,不会显示注释信息
#!/bin/bash

read -p "name:" name
+ read -p name: name
name:nana
read -p "password:" pwd
+ read -p password: pwd
password:123

if [[ $name == "nana" && $pwd == "123" ]];then
	echo "登陆成功"
else
	echo "账号或密码错误"
fi
+ [[ nana == \n\a\n\a ]]
+ [[ 123 == \1\2\3 ]]
+ echo 登陆成功
登陆成功
调试方式2:只调试语法是否有问题,比如if判断少了fi结尾
bash -n login.sh 
# login.sh: line 10: syntax error: unexpected end of file

cat login.sh 
#!/bin/bash

read -p "name:" name
read -p "password:" pwd

if [[ $name == "nana" && $pwd == "123" ]];then
	echo "登陆成功"
else
	echo "账号或密码错误"
调试方式3:仅调试脚本的一部分,用set -x与set +x包含,运行过程中会只打印它们包含的代码段的运行情况
cat login.sh 
#!/usr/bin/env bash
set -x
read -p "请输入您的名字: " name
read -p "请输入您的密码: " pwd
set +x
if [[ "$name" == "egon" && "$pwd" == "123" ]];then
    echo "登录成功"
else
    echo "账号或密码错误"
fi

. login.sh
cat login.sh 
#!/usr/bin/env bash
set -x
read -p "请输入您的名字: " name
read -p "请输入您的密码: " pwd
set +x

if [[ "$name" == "egon" && "$pwd" == "123" ]];then
    echo "登录成功"
else
    echo "账号或密码错误"
++ read -p '请输入您的名字: ' name
请输入您的名字: nana
++ read -p '请输入您的密码: ' pwd
请输入您的密码: 123
++ set +x
-bash: login.sh: line 12: syntax error: unexpected end of file

变量值的三种来源

1. 直接赋值
today=$(date +%F)
echo $today
# 2021-06-15

2. 从位置参数获取变量值
vim b.sh 
#!/bin/bash
echo ${0}
echo $1
echo $2
echo $3
echo $4
echo $5
echo $6
echo $7
echo $8
echo $9
echo ${10}
echo ${11}

bash b.sh a1 a2 a3 a4 a5 a6 a7 a8 a9 a10 a11 
b.sh
a1
a2
a3
a4
a5
a6
a7
a8
a9
a10
a11

企业使用:可以实现脚本的不同功能(服务程序管理脚本-启动功能 关闭功能 重启功能)
bash b.sh start|stop|restart

3. 与用户交互获取值
[root@m01 ~]# read nana
123
[root@m01 ~]# echo $nana
123

[root@m01 ~]# read -p "输入名字:" name				-p->添加提示信息
输入名字:nana
[root@m01 ~]# echo $name
nana

[root@m01 ~]# read -t 2 -p "name" name				-t->限制输入变量值的时间(2s)
name

[root@m01 ~]# read -n 5 name					-n->读取输入字符的个数
aaaaa
[root@m01 ~]# echo $name
aaaaa

预定变量

$*	所有的参数
$@ 	所有的参数
$# 	参数的个数
$$ 	当前进程的PID  # 此外,可以使用只读变量来获取父进程的PID:$PPID、获取执行脚本的用户ID:$UID
$?	上一个命令的返回值 0表示成功	

[root@m01 ~]# vim A.sh
echo $*
echo $@
echo $#
echo $$
[root@m01 ~]# bash A.sh a1 a2 a3 a4 a5
a1 a2 a3 a4 a5
a1 a2 a3 a4 a5
5
17821

[root@m01 ~]# ping -c1 www.baidu.com &> /dev/null
[root@m01 ~]# echo $?
0

$*与$@的差别
[root@m01 ~]# vim B.sh 
#!/bin/bash

for i in "$*"
do 
	echo $i
done

echo "================"

for i in "$@"
do 
	echo $i
done

[root@m01 ~]# bash B.sh 1 2 3 "4 5"
1 2 3 4 5
================
1
2
3
4 5

常量

相对于变量,常量就是不可以被改变的量,即只能读不能改,所以又称之为只读变量

使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。
[root@m01 ~]# x=111
[root@m01 ~]# readonly x
[root@m01 ~]# x=666
-bash: x: readonly variable
Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐