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

3.1.11. 参考手册

https://bash.cyberciti.biz/guide/Main_Page