Linux笔记9——shell编程基础-3

补充

  1. shell解释器是可以手动开启的,可以开启多个shell、也可以开启子shell

  2. 最明显的感觉就是当你新开启一个shell后,你刚才执行的历史命令调用不出来

  3. 使用bash命令可以打开一个新的bash,查看pstree结果中的sshd部分

    [root@localhost ~]# pstree
    systemd─┬─NetworkManager───2*[{NetworkManager}]
    ├─rsyslogd───2*[{rsyslogd}]
    ├─sshd───sshd───sshd───bash───pstree
    ├─systemd───(sd-pam)

    [root@localhost ~]# bash
    [root@localhost ~]# pstree
    systemd─┬─NetworkManager───2*[{NetworkManager}]

    复制代码
         ├─rsyslogd───2*[{rsyslogd}]
         ├─sshd───sshd───sshd───bash───bash───pstree

一、大括号、小括号

  • {}:定义了命令在本bash中运行
  • ():定义了命令在子bash中运行,脱离当前变量环境

注:父bash定义的环境变量能够被子bash继承,但子不传父,且没法继承局部变量

复制代码
[root@localhost ~]# name=lisi
[root@localhost ~]# bash
[root@localhost ~]# echo $name

[root@localhost ~]# exit
exit
[root@localhost ~]# (echo $name)
lisi
#虽然bash和(echo $name)都会创建子Shell,但它们的创建时机和方式有本质区别,这导致了行为的不同
[root@localhost ~]# (name=zhangsan;echo $name)
zhangsan
[root@localhost ~]# echo $name
lisi
#虽然在小括号的子bash中修改了变量值,但不会影响到父bash

{}和()的区别

相同:都是把一串命令放在括号里,并且命令之间用;隔开

不同

  • ()执行命令时需要重开一个子bash去执行,{}在当前shell执行

  • ()命令最后可以不加分号,但{}命令最后不加分好则无法正确执行

  • ()里各命令和括号之间可以没有空格,{}第一个命令和左括号之间必须有一个空格

    #{ } 执行命令时,就在本shell中进行
    [root@localhost ~]# { name=wangwu;echo name;} wangwu [root@localhost ~]# echo name
    wangwu

二、shell变量

  • 变量:即可变的量(变量包含字母、数字、下划线,但数字不能作开头)
  • 声明变量:变量名=值(字符串、常量、命令结果、变量的值,等号两边不能有空格)
  • 调用变量:echo $变量名

注:变量是有类型的,默认是字符串

复制代码
#可以把一个现有变量的值作为变量值赋给变量
$ lujing="$PATH"
$ echo $lujing
#可以把一个命令的结果作为变量值赋给变量
$ shijian=`date`
或:shijian=$(date)
$ echo $shijian
#调用变量值时,为了保证不与后面的字符(字母、数字、下划线)被误判成新的变量名,需要加花括号
进行分隔
$ shijian="$(date)"
$ echo "now time is $shijian ma?"
now time is 2023年 09月 15日 星期五 00:19:48 CST ma?
$ echo "nowtimeis$shijianma?"
nowtimeis?
$ echo "nowtimeis${shijian}ma?"
nowtimeis2023年 09月 15日 星期五 00:19:48 CSTma?
#变量是可以叠加的
$ a=10;b=20
$ echo $a+$b -- 10+20

变量的分类

  • 自定义变量:由用户自由定义变量的名和值
  • 环境变量:保存的值是和系统操作环境相关的数据(一般为系统预先设定)
  • 预定义变量:bash中已经 定义好的变量,变量名不能自定义,作用也是固定的
  • 位置参数变量:用来向脚本中传递参数或数据的,变量名不能自定义,作用是固定的

注:set命令会将当前定义好的变量都给列出来

自定义变量

  • 增:名=值

  • 删:unset 名

  • 改:名=新值

  • 查:echo $变量名

    [root@localhost ~]# shijian=(date) #增 [root@localhost ~]# echo shijian
    2025年 08月 25日 星期一 18:44:16 CST
    [root@localhost ~]# set | grep shijian #查
    shijian='2025年 08月 25日 星期一 18:44:16 CST'
    [root@localhost ~]# unset shijian #删
    [root@localhost ~]# set | grep shijian
    _=shijian
    [root@localhost ~]# echo $shijian

    [root@localhost ~]#

注:用echo输出,无论是没有变量还是有变量但值为空,输出结果是一样的;因此要用set做区分

复制代码
[root@localhost ~]# echo $nnn

[root@localhost ~]# shijian=
[root@localhost ~]# echo $shijian

[root@localhost ~]# set | grep nnn
[root@localhost ~]# set | grep shijian
shijian=
[root@localhost ~]# 

set命令

  • set -u:提示未定义的变量,开启校验模式(或set | grep 变量名,查找)

  • set -x:执行命令前先打印出来(bash -x可以起到相同的效果)

  • set +u:可以取消校验变量名的模式

    [root@localhost ~]# set -u
    [root@localhost ~]# echo nnn #调用没有声明的变量时会报错 -bash: nnn:未绑定的变量 [root@localhost ~]# echo shijian

    [root@localhost ~]# set -x
    ++ printf '\033]0;%s@%s:%s\007' root localhost '~'
    [root@localhost ~]# echo "nihao"

    • echo nihao
      nihao
      ++ printf '\033]0;%s@%s:%s\007' root localhost '~'
      [root@localhost ~]# set +u +x
      #调试脚本时,可以在脚本中写入set -x,每次运行脚本(bash 脚本名)都会先打印
      [root@localhost ~]# cat for1.sh
      #!/bin/bash
      set -x
      for i in 1 2 3 4
      do
      echo $i
      done
      #也可以有问题时打印一次,bash -x 脚本名

环境变量

  • 定义:export 变量名=值

备注:环境变量一般都大写,但一般很少自定义环境变量,都是使用系统设置好的

  • 增:export 名=值(名大写)或名=值 && export 名

  • 删:unset 名

  • 改:名=新值

  • 查:set查看所有变量(普通或环境)或env

    #增
    [root@localhost ~]# SIZE=1000
    [root@localhost ~]# export SIZE

    [root@localhost ~]# export SIZE=1000
    #查
    [root@localhost ~]# set | grep SIZE
    HISTFILESIZE=1000
    HISTSIZE=1000
    SIZE=1000
    _=SIZE=1000

    [root@localhost ~]# env | grep SIZE
    HISTSIZE=1000
    SIZE=1000
    #删
    [root@localhost ~]# unset SIZE
    [root@localhost ~]# env | grep SIZE
    HISTSIZE=1000
    [root@localhost ~]#

1.PATH:存放命令路径

复制代码
#系统中的环境变量
#PATH变量:系统命令存放路径
[root@localhost ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin

#问题:将一个系统外部命令使用命令名就可以执行
方法一:可以考虑把自己写的脚本放入PATH对应的目录内
[root@localhost bik.d]# bash prin.sh 
Bash
also
a
of
[root@localhost bik.d]# cp -a prin.sh /usr/bin/
[root@localhost ~]# chmod +x /usr/bin/prin.sh
[root@localhost ~]# prin.sh
Bash
also
a
of
[root@localhost ~]#

方法二:修改PATH变量的值,将我们存放脚本的目录叠加到PATH变量中
[root@localhost ~]# rm -rf /usr/bin/prin.sh 
[root@localhost ~]# echo $PATH
/root/.local/bin:/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
[root@localhost ~]# PATH=$PATH:/root/bik.d
[root@localhost ~]# echo $PATH
/root/.local/bin:/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bik.d
[root@localhost ~]# chmod +x /root/bik.d/prin.sh 
[root@localhost ~]# prin.sh 
Bash
also
a
of
[root@localhost ~]# 

#永久设置PATH变量:
单用户生效:~/.bash_profile
所有用户生效:/etc/profile
PATH=$PATH:/root/bik.d  #在末行写入命令,保存退出后重载

#相关的配置文件(顺序执行):
/etc/profile => ~/.bash_profile => ~/.bashrc => /etc/bashrc
#修改/etc路径下的配置文件将会应用到整个系统,属于系统级的配置
#修改用户目录下的.bashrc则只是限制在用户应用上,属于用户级设置

2.PS1:命令提示符设置

复制代码
[root@localhost ~]# echo $PS1
[\u@\h \W]\$
  • \u:显示当前用户名

  • \h:显示简写主机名。如默认主机名"localhost",全名是"localhost.localdomain"

  • \W:显示当前所在目录的最后一个目录

  • \:提示符。如果是root提示符为"#",如果是普通用户提示符为""

  • \H:显示完整的主机名。如默认主机名"localhost.localdomain"

  • \d:显示日期,格式为"星期月日"Ø

  • \t:显示24小时制时间,格式为"HH:MM:SS"

  • \T:显示12小时制时间,格式为"HH:MM:SS"

  • \A:显示24小时制时间,格式为"HH:MM"

  • \@:显示12小时制时间,格式为"HH:MM am/pm"

  • \v:显示Bash的版本信息

  • \w:显示当前所在目录的完整名称

  • \#:执行的第几个命令

    [root@localhost ~]# echo $PS1
    [\u@\h \W]$
    [root@localhost ~]# PS1='[\u@\H \w]'
    [root@localhost ~]cd bik.d/
    [root@localhost ~/bik.d]

注:跟系统环境相关的变量,但env命令查不到;自定义PS1时需要使用单引号,否则不生效

永久设置:vim /etc/bashrc

3.LANG:系统语系变量

查:localectl list-locales------查看Linux支持的所有语系

改:localectl set-locale LANG=en_US(退出当前终端后生效)或cat /etc/locale.conf

永久修改:vim /etc/locale.conf

预定义变量

  • $?:判断命令是否正确执行

  • :当前进程的进程号(PID)

    [root@19:52 ~]# echo $$
    878
    [root@19:53 ~]# echo $!

    [root@19:53 ~]# top &
    [1] 1304
    [root@19:53 ~]# echo $!
    1304

位置参数变量

作用:根据调用脚本时传入参数值的位置,进行变量赋值或取值

  • n:n可以是0,1,2,3....,但是10以后要加大括号,0是脚本名
  • \*/@:取所有的值

区别:\*取值是一个整体;@取的每一个值都是可以分开的

实验:编写一个test.sh脚本,输出位置参数

复制代码
[root@20:01 ~]# bash test.sh 1 2 3 4 5 6 7 8 9 10
$0的值是:test.sh
$1的值是:1
$2的值是:2
$10的值是:10

注:$n按顺序取值,但是十以及十以后的值需要加大括号,否则

复制代码
[root@20:03 ~]# bash test.sh 1 2 3 4 5 6 7 8 9 abs
$0的值是:test.sh
$1的值是:1
$2的值是:2
$10的值是:10
复制代码
[root@20:05 ~]# bash test.sh 1 2 3 4 5 6 7 8 9 abs
$0的值是:test.sh
$1的值是:1
$2的值是:2
$10的值是:abs

\*和@取值:在test.sh中写入命令

复制代码
[root@20:08 ~]# bash test.sh 1 2 3 4 5 6 7 8 9 abs
$0的值是:test.sh
$1的值是:1
$2的值是:2
$10的值是:abs
$*的值是1 2 3 4 5 6 7 8 9 abs
$@的值是1 2 3 4 5 6 7 8 9 abs

测试两者的不同,用for循环​​​​​​​