Contents
3.1. 1 基础知识¶
3.1.1. 1 Shell简介¶
Shell 是一个 C 语言编写的脚本语言,它是用户与 Linux 的桥梁,用户输入命令交给 Shell 处理, Shell 将相应的操作传递给内核(Kernel),内核把处理的结果输出给用户。
程序=指令+数据
3.1.2. 2 Shell分类¶
2.1 图形界面 Shell(GUI Shell)¶
GUI 为 Unix 或者类 Unix 操作系统构造一个功能完善、操作简单以及界面友好的桌面环境。主流桌面环境有 KDE,Gnome 等。
2.2 命令行界面 Shell(CLI Shell)¶
CLI 是在用户提示符下键入可执行指令的界面,用户通过键盘输入指令,完成一系列操作。 在 Linux 系统上主流的 CLI 实现是 Bash,是许多 Linux 发行版默认的 Shell。还有许多 Unix 上Shell。
[root@10-234-2-128 pyworkspace]# cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
Shell的分类:
* Bourne Shell(/usr/bin/sh或/bin/sh)
* Bourne Again Shell(/bin/bash)
* C Shell(/usr/bin/csh)
* K Shell(/usr/bin/ksh)
* Shell for Root(/sbin/sh)
脚本命名:
注意:见名知意,后缀规范为.sh
3.1.3. 3 第一个Shell¶
#!/bin/bash
echo "this is my first shell script"
#! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 程序
/bin/bash 指定使用的是那种shell echo在终端打印出内容
3.1.4. 4. 执行Shell的三种方法¶
授予用户执行该脚本文件的权限,使得该程序能够直接执行。
通过调用Shell脚本解释器来执行。
通过source命令来执行。
4.1 直接bash执行¶
[root@shell workspace]# ll
total 4
-rw-r--r-- 1 root root 44 Sep 3 14:16 01-scripts.sh
[root@shell workspace]# cat 01-scripts.sh
#!/bin/bash
echo "this is my first script"
[root@shell workspace]# bash 01-scripts.sh
this is my first script
4.2 ./执行¶
[root@shell workspace]# ./01-scripts.sh
-bash: ./01-scripts.sh: Permission denied
[root@shell workspace]# chmod +x 01-scripts.sh
[root@shell workspace]# ll
total 4
-rwxr-xr-x 1 root root 44 Sep 3 14:16 01-scripts.sh
[root@shell workspace]# ./01-scripts.sh
this is my first script
这种方式默认根据脚本第一行指定的解释器处理,如果没写以当前默认 Shell 解释器执行。
4.3 source执行¶
[root@shell workspace]# source 01-scripts.sh
this is my first script
注意 source 或 . xxx.sh不会开启子shell运行,默认在父shell中执行相关的指令和命令。
3.1.5. 5 Shell变量¶
变量名+内存空间
变量赋值:name=value
弱类型变量,所有变量类型视为字符串类型,对于数值相加自动转换为数组类型,无需实现声明
5.1 变量命名规则¶
命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
中间不能有空格,可以使用下划线(_)。
不能使用标点符号。
不能使用bash里的关键字(可用help命令查看保留关键字)
做到见名知意
环境变量作用范围:当前shell进程及其子进程
本地变量作用范围:当前shell
局部变量作用范围:代码片段
利用export将本地变量导入到环境,扩大作用范围
5.2 系统内置变量¶
在命令行提示符直接执行env、set查看系统或环境变量。env
显示用户环境变量,set 显示 Shell
预先定义好的变量以及用户变量。可以通过 export 导出成用户变量。
还可通过printevn/declare -x
$SHELL 默认 Shell
$HOME 当前用户家目录
$IFS 内部字段分隔符
$LANG 默认语言
$PATH 默认可执行程序路径
$PWD 当前目录
$UID 当前用户 ID
$USER 当前用户
$HISTSIZE 历史命令大小,可通过 HISTTIMEFORMAT 变量设置命令执行时间
$RANDOM 随机生成一个 0 至 32767 的整数
$HOSTNAME 主机名
$DIRSTACK 显示目录栈的栈顶值
$SECOND 记录脚本执行所消耗的时间
用户还可以使用set命令列出所有的环境变量,如下:
[root@linux chapter3]# set | more
演示通过环境变量来获取与当前Shell有关的一些环境变量的值
#! /bin/bash
# 输出命令搜索路径
echo "commands path is $PATH"
# 输出当前的登录名
echo "current login name is $LOGNAME"
# 输出当前用户的主目录
echo "current user's home is $HOME"
# 输出当前的 Shell
echo "current shell is $SHELL"
# 输出当前工作目录
echo "current path is $PWD
[root@192 chapter2]# sh sample03.sh
commands path is /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
current login name is root
current user's home is /root
current shell is /bin/bash
current path is /home/shell_script/chapter2
特殊变量
系统变量 系统变量,Shell常用的系统变量并不多,但却十分有用,特别是在做一些参数检测的时候。下面是Shell常用的系统变量
表示方法 |
描述 |
|---|---|
$n |
$1 表示第一个参数,$2 表示第二个参数 … |
$# |
命令行参数的个数 |
$0 |
当前脚本的名称 |
$? |
前一个命令或函数的返回码 |
$* |
以“参数1参数2参数3……”的形式返回所有参数的值 |
$@ |
以“参数1”“参数2”“参数3”……的形式返回所有参数的值 |
$$ |
本程序的(进程ID号)PID |
$! |
上一个命令的PID |
$_ |
保存之前执行的命令的最后一个参数 |
\(*和\)@的区别:
相同点:都是引用所有参数。
不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 ” * ” 等价于 “1 2 3”(传递了一个参数),而 “@” 等价于 “1” “2” “3”(传递了三个参数)。
变量$#返回传递给脚本的参数的数量,不包括$0,即排除脚本的名称。
$_ 的用法
$ cat sample01.sh
#!/bin/bash
echo "The \$_is $_" # 返回shell的路径或者脚本的路径
uname -a
echo $_ # 返回前一个命令执行的最后一个值
$ ./sample01.sh
The $_is ./sample01.sh
CYGWIN_NT-10.0 DESKTOP-PMJTNGI 3.0.7(0.338/5/3) 2019-04-30 18:08 x86_64 Cygwin
-a
$ sh sample01.sh
The $_is /usr/bin/sh
CYGWIN_NT-10.0 DESKTOP-PMJTNGI 3.0.7(0.338/5/3) 2019-04-30 18:08 x86_64 Cygwin
-a
5.3 设置环境变量永久生效的常用设置文件¶
profile 类型:
* 定义全局变量
* 运行命令或脚本
bashrc 类型:
* 定义本地变量
* 定义命令别名
交互式登录shell:
加载顺序:/etc/profile -> /etc/profile.d/* -> ~/.bash_profile -> ~/.bashrc -> /etc/bashrc
非交互式登录shell:
加载顺序:~/.bashrc -> /etc/bashrc -> /etc/profile.d/*
(1) 用户环境变量配置
/root/.bashrc
/root/.bash_profile
(2) 全局环境变量的配置
/etc/profile
/etc/bashrc # <=== 推荐在此文件中优先设置
/etc/profile.d/
默认情况下,.bash_profile文件常常用来设置环境变量,执行用户的.bashrc文件。下面的代码是某个系统中root用户的.bash_profile文件的内容:
# .bash_profile
# Get the aliases and functions
if [ -f ~/.bashrc ]; then
. ~/.bashrc
fi
# User specific environment and startup programs
PATH=$PATH:$HOME/bin:/usr/pgsql-9.2/bin
export PATH
.bashrc文件包含专属于某个用户的bash的相关信息,当用户登录以及每次打开新的bash时,该文件将被读取并执行。下面的代码是某个系统中root用户的.bashrc的内容:
# .bashrc
# User specific aliases and functions
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
该文件主要用来定义别名和函数,同时该文件还会调用/etc/bashrc文件
.bash_logout文件在当前用户每次退出Shell时执行。如果没有特别的要求,该文件的内容通常为空。
etc/bashrc与sh中的/etc/profile文件非常相似,它是所有使用bash的用户共同使用的文件。当任何用户在登录bash后,都会执行该文件中的代码
5.4 用户自定义变量¶
普通变量
[root@shell workspace]# var=normal
[root@shell workspace]# echo $var
normal
临时环境变量
在当前shell下定义的变量,只对当前shell有效,
新的bash已经其子bash无法使用当前定义的shell,
如果在本shell存在的情况下,使用export来导入到系统变量中,
如果当前shell终端终端,那么导入的变量将全部失效,永久生效需要写入linux配置文件中。
[root@k8s-master ~]# export NAME1=hujianli1
[root@k8s-master ~]# declare -x NAME2=hujianli2
[root@k8s-master ~]# NAME3=hujianli3;export NAME3
[root@k8s-master ~]# env|grep NAME*
HOSTNAME=k8s-master
NAME=hujianli2
NAME3=hujianli3
NAME2=hujianli2
NAME1=hujianli1
只读变量
[root@shell ~]# var='test'
[root@shell ~]# echo $var
test
[root@shell ~]# readonly var
[root@shell ~]# var='bbb'
-bash: var: readonly variable
删除变量
unset variable_name
变量被删除后不能再次使用。unset 命令不能删除只读变量。
5.5 变量引用¶
= 变量赋值
+= 变量相加
[root@shell data]# var=123
[root@shell data]# var+=234
[root@shell data]# echo $var
123234
为避免特殊字符及变量与字符连接使用,建议引用变量添加大括号
5.6 变量的作用域¶
1.全局变量
通常认为,全局变量是使用范围较大的变量,它不仅限于某个局部使用。在Shell语言中,全局变量可以在脚本中定义,也可以在某个函数中定义。在脚本中定义的变量都是全局变量,其作用域为从被定义的地方开始,一直到Shell脚本结束或者被显式地删除。
全局变量的使用方法
#! /bin/bash
# 定义函数
func()
{
# 输出变量 x 的值
echo "$v1"
# 修改变量 x 的值
v1=200
}
# 在脚本中定义变量 x
v1=100
# 调用函数
func
# 输出变量 x 的值
echo "$v1"
函数内部定义全局变量的方法
#! /bin/bash
# 定义函数
func()
{
# 在函数内部定义变量
v2=200
}
# 调用函数
func
# 输出变量的值
echo "$v2"
2.局部变量
与全局变量相比,局部变量的使用范围较小,通常仅限于某个程序段访问,例如函数内部。在Shell语言中,可以在函数内部通过local关键字定义局部变量,另外,函数的参数也是局部变量。
#! /bin/bash
# 定义函数
func()
{
# 使用 local 关键字定义局部变量
local v2=200
}
# 调用函数
func
# 输出变量的值
echo "$v2"
从上面的执行结果可以得知,由于在函数内部使用local关键字显式地定义了局部变量,所以在函数外面不能获得该变量的值。echo语句仅仅输出了空值。
[root@192 chapter2]# sh sample01.sh
演示全局变量和局部变量的区别
#! /bin/bash
# 定义函数
func()
{
# 输出全局变量 v1 的值
echo "global variable v1 is $v1"
# 定义局部变量 v1
local v1=2
# 输出局部变量 v1 的值
echo "local variable v1 is $v1"
}
# 定义全局变量 v1
v1=1
# 调用函数
func
# 输出全局变量 v1 的值
echo "global variable v1 is $v1"
[root@192 chapter2]# sh sample02.sh
global variable v1 is 1
local variable v1 is 2
global variable v1 is 1
3.1.6. 6 引号¶
单引号是告诉 Shell 忽略特殊字符,而双引号则解释特殊符号原有的意义,比如$、!。
[root@xuel-tmp-shell www]# var1="aaa"
[root@xuel-tmp-shell www]# echo '$var1'
$var1
[root@xuel-tmp-shell www]# echo "$var1"
aaa
[root@xuel-tmp-shell www]# var2="aa"
[root@xuel-tmp-shell www]# var3='bb $var2'
[root@xuel-tmp-shell www]# echo $var3
bb $var2
[root@xuel-tmp-shell www]# var4="bb $var2"
[root@xuel-tmp-shell www]# echo $var4
bb aa
3.1.7. 7 Shell脚本中的注释和风格¶
单行注释使用
如果需要多行注释内容的话,则在每行注释的开头都要加上“#”,例如:
# 注释1 # 注释2 # 注释3
多行注释固定函数格式
#方式一
:<<EOF
内容...
内容...
EOF
#方式二
#用:(冒号), 做一个假命令来从一个here document中接收输出 用于区块注释
cat > /dev/null <<EOF
xxxxx
yyyyy
xyxyxyx
EOF
#方式三
[ 0 -eq 1 ] && {
echo "这是注释1!"
echo "这是注释2!"
示例
<<COMMENT
Author:Jacob
Date:2018-8-8
Version:1.0
Description:This is my first script
COMMENT
3.1.8. 8 Shell程序的退出状态¶
在UNIX或者Linux中,每个命令都会返回一个退出状态码。退出状态码是一个整数,其有效范围为0~255。通常情况下,成功的命令返回0,而不成功的命令返回非0值。非0值通常都被解释成一个错误码。运行良好的UNIX命令、程序和工具都会返回0作为退出码来表示成功,偶尔也会有例外。
同样,Shell脚本中的函数和脚本本身也会返回退出状态码。在脚本或者是脚本函数中执行的最后的命令会决定退出状态码。另外,用户也可以在脚本中使用exit语句将指定的退出状态码传递给Shell。
#-----------------------------/chapter1/sample02.sh------------
#!/bin/sh
echo "hello world"
# 退出状态为 0, 因为命令执行成功
echo $?
# 无效命令
abc
# 非零的退出状态 , 因为命令执行失败
echo $?
echo
# 返回 120 退出状态给 shell
exit 120
[root@192 day01]# vim sample02.sh
[root@192 day01]# sh sample02.sh
hello world
0
sample02.sh:行6: abc: 未找到命令
127
[root@192 day01]# echo $?
120
3.1.9. 9.命令替换¶
所谓命令替换,是指在Shell程序中,将某个Shell命令的执行结果赋给某个变量。在bash中,有两种语法可以进行命令替换,分别使用反引号和圆括号,如下:
'shell_command'
$(shell_command)
3.1.10. 10.转义¶
反斜线将屏蔽该字符的特殊意义,使得Shell按照该字符的字面意义来解释。
[root@linux chapter3]# echo $SHELL
/bin/bash
[root@linux chapter3]# echo \$SHELL
$SHELL