LINUX | Shell Script 编程 | 变量

Shell回顾

Shell是什么

  • 通过Linux内核 可以实现对CPU、内存等硬件的调用
  • Linux内核 的沟通, 则需要借助Shell
  • Shell 是一个命令行解释器: 接收应用程序 / 用户命令, 相应地调用操作系统内核
  • 把命令一行一行地写进一个文件, Shell 同样会一行一行地执行, 这样的一个可执行文件 , 即为脚本 , 各种复杂的流程控制因此而得到实现

查看Shell

  • 查看当前系统提供支持的Shell解析器
(base) kv@ubuntu:~$ cat /etc/shells
# /etc/shells: valid login shells
/bin/sh
/bin/dash
/bin/bash
/bin/rbash
/usr/bin/screen
  • 查看当前默认的Shell解析器
(base) kv@ubuntu:~$ echo $SHELL
/bin/bash
  • 查看进程时, 显示的也会是bash
(base) kv@ubuntu:~$ ps
   PID TTY          TIME CMD
  2892 pts/6    00:00:00 bash
  4149 pts/6    00:00:00 ps

上手Shell脚本

脚本格式

  • 后缀名默认.sh, 但实际上, 只要可执行文件的内容是按照Shell语法写出的, 都是可以按Shell脚本来执行
  • #后可进行注释, 而脚本中的第一行注释, 或者说脚本的开头, 是用来选择当前命令行的解析器, 例如
#!/bin/sh

或者是

#!/bin/bash

脚本的执行方式

  • 创建一个名为helloworld.sh的Shell脚本文件, 内容为
    1 #!/bin/bash
    2 echo "Hello world!"
    
  1. bash命令 / sh命令 + 可执行文件的相对路径 / 绝对路径
  • 具体执行结果
(base) kv@ubuntu:~/scripting$ bash helloworld.sh
Hello world!
  • 或者
(base) kv@ubuntu:~$ sh scripting/helloworld.sh
Hello world!
  1. 具有可执行权限x时, 直接输入脚本的相对路径 / 绝对路径
  • 当可执行文件没有可执行权限时, 需要使用chmod 命令及时地添加
(base) kv@ubuntu:~$ scripting/helloworld.sh
bash: scripting/helloworld.sh: Permission denied
(base) kv@ubuntu:~$ cd scripting 
(base) kv@ubuntu:~/scripting$ ls -l 
total 4
-rw-rw-r-- 1 kv kv 32 Nov  4 19:03 helloworld.sh
(base) kv@ubuntu:~/scripting$ chmod u+x helloworld.sh
(base) kv@ubuntu:~/scripting$ ls -l
total 4
-rwxrw-r-- 1 kv kv 32 Nov  4 19:03 helloworld.sh
  • 执行当前目录下的可执行文件时, 需要使用下面的方式
  • . 表示当前目录下, 那么这种方式本质上也就是通过相对路径来执行
(base) kv@ubuntu:~/scripting$ ./helloworld.sh
Hello world!
  • 否则系统将把文件名认为是一条命令来执行
(base) kv@ubuntu:~/scripting$ helloworld.sh
helloworld.sh: command not found
  • 使用可执行文件的绝对路径来直接执行
(base) kv@ubuntu:~$ /home/kv/scripting/helloworld.sh
Hello world!
  • 第一种执行方式所用到的脚本文件路径, 相当于传给命令的参数, 不涉及可执行权限的问题
  • 第二种执行方式是脚本自己本身来执行, 因此必须要有可执行权限
  1. source 命令 / . 命令 + 可执行文件的相对路径 / 绝对路径
  • source 命令和. 命令是Shell 内嵌的一个命令
    (base) kv@ubuntu:~/scripting$ type source
    source is a shell builtin
    (base) kv@ubuntu:~/scripting$ type .
    . is a shell builtin
    
  • 具体的执行结果
(base) kv@ubuntu:~$ source scripting/helloworld.sh
Hello world!
(base) kv@ubuntu:~$ cd scripting
(base) kv@ubuntu:~/scripting$ . helloworld.sh
Hello world!
  • 前两种方式都是又启动了一个子Shell进程, 都是在子Shell中执行脚本
  • 而这种方式则是直接在当前的Shell中进行执行

Shell编程中的变量

  • 使用bash 命令可在当前的Shell中创建子Shell, 并使用exit 命令退出子Shell
    (base) kv@ubuntu:~/scripting$ ps -f
    UID         PID   PPID  C STIME TTY          TIME CMD
    kv         2892   2885  0 18:42 pts/6    00:00:00 bash
    kv         5049   2892  0 20:55 pts/6    00:00:00 ps -f
    (base) kv@ubuntu:~/scripting$ bash
    (base) kv@ubuntu:~/scripting$ ps -f
    UID         PID   PPID  C STIME TTY          TIME CMD
    kv         2892   2885  0 18:42 pts/6    00:00:00 bash
    kv         5050   2892  1 20:56 pts/6    00:00:00 bash
    kv         5130   5050  0 20:56 pts/6    00:00:00 ps -f
    (base) kv@ubuntu:~/scripting$ exit
    exit
    (base) kv@ubuntu:~/scripting$ ps -f
    UID         PID   PPID  C STIME TTY          TIME CMD
    kv         2892   2885  0 18:42 pts/6    00:00:00 bash
    kv         5131   2892  0 20:56 pts/6    00:00:00 ps -f
    
  • Shell子Shell 所涉及到的、最为关键的问题是环境变量的继承关系
    • 子Shell 中设置的当前变量, 在父Shell 中是不可见的
    • 子Shell 中是无法更改父Shell 的全局变量的

什么是变量

  • 希望临时地在当前Shell会话中保存的一些信息, 即为(环境)变量, 又可以分为
    • 系统预定义变量
    • 用户自定义变量
  • 或者有可以将变量划分为
    • 全局变量: 对所有的子Shell同样有效
    • 局部变量: 只对当前的Shell有效
  • 查看当前的用户、主目录、工作目录, 以及使用的Shell解析器等系统变量
    (base) kv@ubuntu:~/scripting$ echo $USER
    kv
    (base) kv@ubuntu:~/scripting$ echo $HOME
    /home/kv
    (base) kv@ubuntu:~/scripting$ echo $PWD
    /home/kv/scripting
    (base) kv@ubuntu:~/scripting$ echo $SHELL
    /bin/bash
    
  • 使用env命令可以查看系统定义的全局变量
    (base) kv@ubuntu:~/scripting$ env
    XDG_VTNR=7
    XDG_SESSION_ID=c2
    CLUTTER_IM_MODULE=xim
    XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/kv
    SESSION=ubuntu
    GPG_AGENT_INFO=/home/kv/.gnupg/S.gpg-agent:0:1
    TERM=xterm-256color
    ... ... 
    
  • set命令可以查看所有Shell中的环境变量, 包括用户自定义的变量, 以及关于这个变量的函数, 由此得到的结果是最为全面的
  • 使用printenv 命令, 后面可直接跟变量名, 无需$ 符号
  • 这只是将变量的信息打印出来, 如果要使用这个变量, 还是要跟上$ 符号的
(base) kv@ubuntu:~/scripting$ printenv DISPLAY
:0

定义环境变量

  • 对于环境变量的定义,主要有以下几个方面需要注意

    1. 变量名称可以由大小写字母、数字和下划线组成, 但是不能以数字开头
    2. 变量赋值表达式的等号左右两侧, 不能有空格 ! ! !
    3. 无需指定变量类型, 默认是字符串类型, 无法直接进行数值运算
    4. 给变量赋的值中, 包含空格则需要用引号引起来该值, 否则将被识别为命令
  • 变量赋值的基本操作

    (base) kv@ubuntu:~$ variable=Helloworld!
    (base) kv@ubuntu:~$ echo $variable
    Helloworld!
    (base) kv@ubuntu:~$ variable=Hello world!
    world!: command not found
    (base) kv@ubuntu:~$ variable='Hello world!'
    (base) kv@ubuntu:~$ echo $variable
    Hello world!
    

确认全局和局部变量

  • 子Shell中查看变量variable是否存在
    (base) kv@ubuntu:~$ ps -f
    UID         PID   PPID  C STIME TTY          TIME CMD
    kv         2229   2222  0 22:36 pts/17   00:00:00 bash
    kv         2438   2229  0 22:52 pts/17   00:00:00 ps -f
    (base) kv@ubuntu:~$ bash
    (base) kv@ubuntu:~$ ps -f
    UID         PID   PPID  C STIME TTY          TIME CMD
    kv         2229   2222  0 22:36 pts/17   00:00:00 bash
    kv         2439   2229  2 22:52 pts/17   00:00:00 bash
    kv         2519   2439  0 22:52 pts/17   00:00:00 ps -f
    (base) kv@ubuntu:~$ echo $variable
    
    (base) kv@ubuntu:~$ exit
    exit
    
  • 从结果上看, 变量variable并不存在于子Shell 中, 因此, 变量variable是一个局部变量
  • 通过表达式定义的变量, 都是局部变量
  • 使用export 命令可以直接定义全局变量, 或者将局部变量更改为全局变量
    (base) kv@ubuntu:~$ export variable
    (base) kv@ubuntu:~$ ps -f
    UID         PID   PPID  C STIME TTY          TIME CMD
    kv         2229   2222  0 22:36 pts/17   00:00:00 bash
    kv         2530   2229  0 22:56 pts/17   00:00:00 ps -f
    (base) kv@ubuntu:~$ bash
    (base) kv@ubuntu:~$ ps -f
    UID         PID   PPID  C STIME TTY          TIME CMD
    kv         2229   2222  0 22:36 pts/17   00:00:00 bash
    kv         2531   2229  1 22:56 pts/17   00:00:00 bash
    kv         2611   2531  0 22:56 pts/17   00:00:00 ps -f
    (base) kv@ubuntu:~$ echo $variable
    Hello world!
    
  • 通过export 命令确实实现了在子Shell中调用变量variable
  • 但需要注意的是, 在子Shell 中更改变量variable, 并不会在父Shell 中生效
    (base) kv@ubuntu:~$ variable='Hello linux!'
    (base) kv@ubuntu:~$ echo $variable
    Hello linux!
    (base) kv@ubuntu:~$ exit
    exit
    (base) kv@ubuntu:~$ ps -f
    UID         PID   PPID  C STIME TTY          TIME CMD
    kv         2229   2222  0 22:36 pts/17   00:00:00 bash
    kv         2633   2229  0 23:00 pts/17   00:00:00 ps -f
    (base) kv@ubuntu:~$ echo $variable
    Hello world!
    

反观执行方式

  • 创建全局变量jesse和局部变量walter
    (base) kv@ubuntu:~$ export jesse='My name is Jesse.'
    (base) kv@ubuntu:~$ echo $jesse
    My name is Jesse.
    (base) kv@ubuntu:~$ walter='My name is Heisenberg.'
    (base) kv@ubuntu:~$ echo $walter
    My name is Heisenberg.
    
  • 创建的可执行文件fatherandson.sh, 写入下面的内容
    1 #!/bin/bash                                                                  
    2  
    3 echo $jesse
    4 echo $walter
    
  • 调整文件的可执行权限后, 分别使用相对路径和source 命令的方式来执行文件
    (base) kv@ubuntu:~/scripting$ ./fatherandson.sh
    My name is Jesse.
    
    (base) kv@ubuntu:~/scripting$ source fatherandson.sh
    My name is Jesse.
    My name is Heisenberg.
    
  • 使用相对路径的方式来执行文件时, 变量walter并非全局变量, 因此不存在执行时创建子Shell
  • source 命令直接在当前的Shell中执行, 因此变量walter是存在的

使用unset 命令来删除变量

  • 将变量作为参数传给unset 命令
    (base) kv@ubuntu:~$ jesse='My name is Jesse.'
    (base) kv@ubuntu:~$ echo $jesse
    My name is Jesse.
    (base) kv@ubuntu:~$ set | grep jesse
    jesse='My name is Jesse.'
    (base) kv@ubuntu:~$ unset jesse
    base) kv@ubuntu:~$ echo $jesse
    
    (base) kv@ubuntu:~$ set | grep jesse
    (base) kv@ubuntu:~$ 
    

创建只读变量

  • 使用readonly命令, 可以定义只读变量
  • 该变量的值将无法更改, 且该变量无法由unset命令来撤销
    (base) kv@ubuntu:~$ readonly y=2023
    (base) kv@ubuntu:~$ echo $y
    2023
    (base) kv@ubuntu:~$ y=2024
    bash: y: readonly variable
    (base) kv@ubuntu:~$ unset y
    bash: unset: y: cannot unset: readonly variable
    

特殊变量

特殊变量$n

  • $n表示传入可执行文件的第n个参数, $6即表示第6个参数
  • $0表示执行脚本的路径
  • 第10个位置及以后的参数, 需要用{}括起来, 比如${10}
  • 创建可执行文件parameter.sh, 其内容为
    1 #!/bin/bash                                                                 
    2  
    3 echo '==========$n=========='
    4 echo script path: $0
    5 echo 1st parameter: $1
    6 echo 2nd parameter: $2
    
  • 设置好可执行权限后, 输入相对路径来执行该文件
    (base) kv@ubuntu:~/scripting$ ./parameter.sh
    ==========$n==========
    script path: ./parameter.sh
    1st parameter:
    2nd parameter:
    (base) kv@ubuntu:~/scripting$ ./parameter.sh 2023
    ==========$n==========
    script path: ./parameter.sh
    1st parameter: 2023
    2nd parameter:
    (base) kv@ubuntu:~/scripting$ ./parameter.sh 2023 11.05
    ==========$n==========
    script path: ./parameter.sh
    1st parameter: 2023
    2nd parameter: 11.05
    

特殊变量$#

  • $#可以获取输入参数的个数
  • 结合条件和循环语句, 可以使脚本实现更为丰富的功能
  • 在可执行文件parameter.sh 中添加下面的内容
    8 echo '==========$#=========='
    9 echo number of parameters: $#
    
  • 再次执行该文件
    (base) kv@ubuntu:~/scripting$ ./parameter.sh
    ==========$n==========
    script path: ./parameter.sh
    1st parameter:
    2nd parameter:
    ==========$#==========
    number of parameters: 0
    (base) kv@ubuntu:~/scripting$ ./parameter.sh 2022
    ==========$n==========
    script path: ./parameter.sh
    1st parameter: 2022
    2nd parameter:
    ==========$#==========
    number of parameters: 1
    (base) kv@ubuntu:~/scripting$ ./parameter.sh 2022 11.05
    ==========$n==========
    script path: ./parameter.sh
    1st parameter: 2022
    2nd parameter: 11.05
    ==========$#==========
    number of parameters: 2
    (base) kv@ubuntu:~/scripting$ ./parameter.sh 2022 11.05 15:25
    ==========$n==========
    script path: ./parameter.sh
    1st parameter: 2022
    2nd parameter: 11.05
    ==========$#==========
    number of parameters: 3
    

特殊变量$*

  • $*可以将所有参数看成一个整体 / 一个输入, 或者说, 得到的是所有参数的字符串
  • 在可执行文件parameter.sh 中添加下面的内容
    11 echo '==========$*=========='
    12 echo all of parameters: $* 
    
  • 再次执行该文件
    (base) kv@ubuntu:~/scripting$ ./parameter.sh 2023 11.05 15:43
    ==========$n==========
    script path: ./parameter.sh
    1st parameter: 2023
    2nd parameter: 11.05
    ==========$#==========
    number of parameters: 3
    ==========$*==========
    all of parameters: 2023 11.05 15:43
    

特殊变量$@

  • $@相当于将所有参数放入一个列表
  • 这必然会在后续会涉及到判断、循环语句
  • 在可执行文件parameter.sh 中添加下面的内容
    14 echo '==========$#=========='
    15 echo list of parameters: $@
    
  • 再次执行该文件
    (base) kv@ubuntu:~/scripting$ ./parameter.sh 2023 11.05 15:43
    ==========$n==========
    script path: ./parameter.sh
    1st parameter: 2023
    2nd parameter: 11.05
    ==========$#==========
    number of parameters: 3
    ==========$*==========
    all of parameters: 2023 11.05 15:43
    ==========$#==========
    list of parameters: 2023 11.05 15:43
    

特殊变量#?

  • #?可以返回最后一次执行命令的返回状态
  • #?为0, 表示上一个命令被正确执行
    (base) kv@ubuntu:~/scripting$ ./parameter.sh 
    ==========$n==========
    script path: ./parameter.sh
    1st parameter:
    2nd parameter:
    ==========$#==========
    number of parameters: 0
    ==========$*==========
    all of parameters:
    ==========$#==========
    list of parameters:
    (base) kv@ubuntu:~/scripting$ echo $?
    0
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值