[ Content contribution] 基于deepin的shell编程-上
Tofloor
poster avatar
天阁创客official
deepin
2023-12-30 01:38
Author

基于deepin的shell编程-无作者.png


版权授予:哔哩哔哩-TIANGESEC工作室、微信公众号-TIANGESEC工作室

联系作者:[email protected](QQ:1072441436)

错误反馈:请发邮箱[email protected],请使用Word将错误写下,并附上截图,放置在邮箱附件中,改写反馈。

优化建议:请发邮箱[email protected],请使用Word需要改进的地方写下,并附上截图;若有内容添加建议,请在word文件中表明,并放置在邮箱附件中,感谢建议。


基于deepin的shell编程 更新日志

版本号带有 Update的表示为大体内容没有完成,持续更新中

版本号带有 Release的表示代替大体内容已经完成,待反馈和优化以及增加内容

版本号里面带有 Alpha的代表内容在修改中

 版本号解读:
 V0.1--->是内容版本的更替,update.23.12.4是更新日期,release23.12.4是发布日期,alpha23.12.4是修改日期

版本更新V0.1.update23.12.28.:

更新内容:1.1进程列表-2.9数组变量

版本更新V0.1.update23.12.29:

更新内容:3shell运算符-11.7其他选项


Shell的基本功能

Deepin的Shell是Deepin操作系统中的一个重要组成部分,它为用户提供了一个与操作系统交互的界面。Shell是一种命令行解释器,用户可以通过它输入命令来执行各种操作,如文件管理、程序运行、系统配置等。

在Deepin操作系统中,Shell通常是Bash(Bourne-Again SHell)的一个版本,这是大多数Linux发行版中最常用的Shell。Bash具有强大的脚本语言能力,支持各种命令行操作,并且可以编写复杂的脚本程序。

用户可以通过Shell执行各种Linux命令,编写脚本自动化任务,以及进行系统管理和配置。Shell也是许多Linux发行版中默认的命令行解释器,因此,熟悉Shell对于Linux用户来说非常重要。在Deepin中,用户可以通过图形界面中的终端应用程序或通过系统的命令行界面来访问和使用Shell。

不同发行版本的Linux内置使用的默认shell是不一样的,有些是bash,有些是zsh,还有其他的,Ubuntu Linux就是使用的bash,kali Linux使用的是zsh。在后面使用父子shell的时候就可以体现出来。不同shell里面的语法大同小异。他们有区别,但不是没有关系。

1.1 进程列表

在使用shell命令的时候,在中间加上分号(;)即可实现同时操作多条命令,来提高效率,记得命令与命令之间要空格。进程列表是命令分组的一种。

 zql@zql-PC:~$ pwd ; ls ; ll
 /home/zql
 code  com.hmja.ccompare  Desktop  Documents  Downloads  gcadlog  Music  Pictures  Videos
 总计 36
 drwxr-xr-x 3 zql zql 4096 11月 5日 13:17 code
 drwxr-xr-x 2 zql zql 4096 10月 6日 16:43 com.hmja.ccompare
 drwxr-xr-x 2 zql zql 4096 12月28日 19:38 Desktop
 drwxr-xr-x 2 zql zql 4096 10月 9日 18:06 Documents
 drwxr-xr-x 2 zql zql 4096 2023年 2月 7日 Downloads
 drwxr-xr-x 2 zql zql 4096 10月 9日 18:06 gcadlog
 drwxr-xr-x 2 zql zql 4096 2023年 2月 7日 Music
 drwxr-xr-x 4 zql zql 4096 10月 6日 16:47 Pictures
 drwxr-xr-x 2 zql zql 4096  7月 7日 10:11 Videos

1.2 优先级

  • 第一顺位执行用绝对路径或相对路径执行的命令。
  • 第二顺位执行别名。
  • 第三顺位执行Bash的内部命令。
  • 第四顺位执行按照$PATH环境变量定义的目录查找顺序找到的第一个命令。

1.3 Bash常用的快捷键

快捷键 作用
CTRL+A 把光标移动到命令行开头。如果我们输入的命令过长,想要把光标移动到命令行开头时使用
CTRL+E 把光标移动到命令行结尾
CTRL+C 强制终止当前的命令
CTRL+L 清屏,相当于clear命令
CTRL+U 删除或剪切光标之前的命令。我输入了一行很长的命令,不用使用退格键一个一个字符的删除,使用这个快捷键会更加方便
CTRL+K 删除或剪切光标之后的内容
CTRL+Y 粘贴CTRL+U或CTRL+K剪切的内容
CTRL+R 在历史命令中搜索,按下CTRL+R之后,就会出现搜索界面,只要输入搜索内容,就会从历史命令中搜索
CTRL+D 退出当前终端
CTRL+Z 暂停,放入后台
CTRL+S 暂停屏幕输出
CTRL+Q 回复屏幕输出

1.4 重定向

1.4.1 Bash的标准输入和输出

设备 设备文件名 文件描述符 类型
键盘 /dev/stdin 0 标准输入
显示器 /dev/stdout 1 标准输出
显示器 /dev/stderr 2 标准错误输出

1.4.2 输出重定向

 zql@zql-PC:~$ ls >> abc
 zql@zql-PC:~$ pwd >> abc
 zql@zql-PC:~$ cat abc
 abc
 code
 com.hmja.ccompare
 Desktop
 Documents
 Downloads
 gcadlog
 Music
 Pictures
 Videos
 /home/zql
 zql@zql-PC:~$

1.5 多命令执行符

1.5.1 分号;

语法

 commend1 ; commend2

注意:

在不同的命令之间添加分号即可,当有错误的命令在里面的时候它可以不影响执行,命令之间没有逻辑关系

 zql@zql-PC:~$ ls ; date ; cd /home
 abc  code  com.hmja.ccompare  Desktop  Documents  Downloads  gcadlog  Music  Pictures  Videos
 2023年 12月 28日 星期四 20:49:04 CST
 zql@zql-PC:/home$

可以看见,以上命令全部执行了,错误的命令也会执行,跑代码就很方便了

1.5.2 逻辑符&&

语法

 commend1 && commend2

注意:

改用法和上面的分号的用法区别是双&&前一条命令要正确执行后面的命令才会执行,第一条命令错误执行时,第二条命令不会执行。

 [root@Lisa home]# ls && echo 'yes'
 hacker
 yes
 [root@Lisa home]# ls && his
 hacker
 bash: his: command not found...
 [root@Lisa home]# lsls && echo 'yes'
 bash: lsls: command not found...

1.5.3 逻辑符||

语法

 commend1 || commend2

注意:

当第一个命令正确执行后,第二个就不会执行,当第一个命令执行不正确的时候,第二个命令就会执行。

 zql@zql-PC:/home$ ls && echo 'yes' || echo 'no'
 zql
 yes
 zql@zql-PC:/home$ lsiuhb && echo 'yes' || echo 'no'
 -bash: lsiuhb:未找到命令
 no
 zql@zql-PC:/home$

1.6 Bash特殊符号

符号 作用
‘’ 单引号在单引号中所有的特殊符号,如“$”和+“”(反引号)都没有特殊含义,所有的符号都会失去意义
“” 双引号在双引号中特殊符号都没有特殊含义,但是“$”、“~”和“\”是例外,拥有“调用变量的值”、“引用命令”和“转义符”的特殊含义
`` 反引号括起来的内容是系统命令,在Bash中会先执行它。和()作用一样,不过推荐使用**(0,因为反引号非常容易看错**
$() 和反引号作用一样,用来引用系统命令
() 用于一串命令执行时,()中的命令会在子Shell中运行
{} 用于一串命令执行时,{}}中的命令会在当前Shell中执行。也可以用于变量变形与替换
[] 用于变量的测试
# 在shell脚本里面表示注释
$ 用于调用变量的值,如需要调用变量name的值时,需要用$name的方式得到的变量的值
\ 转义符,跟在之后的特殊符号将失去特殊含义,变为普通字符。如$将输出“$”符号,而不当做是变量引用

 #反引号``
 zql@zql-PC:/home$ date
 2023年 12月 28日 星期四 20:51:23 CST
 zql@zql-PC:/home$ a=date
 zql@zql-PC:/home$ echo $a
 date
 zql@zql-PC:/home$ a=`date`
 zql@zql-PC:/home$ echo $a
 2023年 12月 28日 星期四 20:51:44 CST
 zql@zql-PC:/home$ b=$(ls /home)
 zql@zql-PC:/home$ echo $b
 zql
 zql@zql-PC:/home$ echo "\$name"
 $name
 zql@zql-PC:/home$

1.7 父子shell

什么是父shell,什么是子shell,看看下面这张图片,当我们使用pstree命令的时候,我我们可以看到这个命令是在shell的进程下面,这里为什么有两个bash,是因为我们在命令行界面运行了bash,他就要单独开了一个bash在父shell下面,所以前面的bash就是父shell,后面的bash就是子shell,当前进入子shell后,你的历史命令就会消失。
屏幕截图 2023-01-04 171145.png

 #当前的进程为ps和zsh
 zql@zql-PC:/home$ ps --forest
     PID TTY          TIME CMD
    2725 pts/1    00:00:00 bash
    3474 pts/1    00:00:00  \_ ps
 zql@zql-PC:/home$
 
 #进入子shell,当前进程里面多了个\_ zsh
 zql@zql-PC:/home$ bash
 zql@zql-PC:/home$ ps --forest
     PID TTY          TIME CMD
    2725 pts/1    00:00:00 bash
    3502 pts/1    00:00:00  \_ bash
    3535 pts/1    00:00:00      \_ ps
 zql@zql-PC:/home$
 
 #退出子shell,再次查看当前的进程
 zql@zql-PC:/home$ exit
 exit
 zql@zql-PC:/home$ ps --forest
     PID TTY          TIME CMD
    2725 pts/1    00:00:00 bash
    3582 pts/1    00:00:00  \_ ps
  • ()执行一串命令时,需要重新开一个子shell进行执行;
  • {}执行一串命令时,是在当前shell执行;
  • ()和}都是把一串的命令放在括号里面,并且命令之间用;号隔开;
  • ()最后一个命令可以不用分号;
  • {}最后一个命令要用分号;
  • {}的第一个命令和左括号之间必须要有一个空格;
  • ()里的各命令不必和括号有空格;
  • ()和{}中括号里面的某个命令的重定向只影响该命令,但括号外的重定向则影响到括号里的
  • 所有命令;


image-20231228205509345.png

我们来看看上面的代码,我们在shell里面定义了一个变量name,值为zhong,当我们使用小括号执行的时候就变了,这是为什么,这里不是覆盖前面的值,而是在小括号里面的命令开了一个子shell,我们当前的shell就可以看作为父shell,所以,我们再次执行命令的时候看到的值还是zhong,如果是赋值被覆盖,那么最后一条命令就还是1;
image-20231228205642920.png

当我们使用大括号的时候,他执行的命令就是在父shell里面执行的,而且必须注意的是,命令前后必须空格,否者就会像最后一行一样,语法是错误的。

查看当前是否使用了子shell还可以使用echo $BASH_SUBSHELL,注意不一定是BASH_SUBSHELL,要根据你当前使用的Linux默认的shell来命名,比如kali就是ZSH_SUBSHELL,如何查看当前使用的是bash还是其他的shell方式有很多,比如ps进程查看等。

zql@zql-PC:~$ pwd ; ls hallo* ; ll ; echo $BASH_SUBSHELL
/home/zql
hallo.c  hallo.cpp  hallo.java  hallo.md  hallo.py  hallo.sh  hallo.tar  hallo.txt
总计 40
-rw-r--r-- 1 zql zql   95 12月28日 20:48 abc
drwxr-xr-x 3 zql zql 4096 11月 5日 13:17 code
drwxr-xr-x 2 zql zql 4096 10月 6日 16:43 com.hmja.ccompare
drwxr-xr-x 2 zql zql 4096 12月28日 19:38 Desktop
drwxr-xr-x 2 zql zql 4096 10月 9日 18:06 Documents
drwxr-xr-x 2 zql zql 4096 2023年 2月 7日 Downloads
drwxr-xr-x 2 zql zql 4096 10月 9日 18:06 gcadlog
-rw-r--r-- 1 zql zql    0 12月28日 20:57 hallo.c
-rw-r--r-- 1 zql zql    0 12月28日 20:58 hallo.cpp
-rw-r--r-- 1 zql zql    0 12月28日 20:57 hallo.java
-rw-r--r-- 1 zql zql    0 12月28日 20:58 hallo.md
-rw-r--r-- 1 zql zql    0 12月28日 20:57 hallo.py
-rw-r--r-- 1 zql zql    0 12月28日 20:57 hallo.sh
-rw-r--r-- 1 zql zql    0 12月28日 20:58 hallo.tar
-rw-r--r-- 1 zql zql    0 12月28日 20:58 hallo.txt
drwxr-xr-x 2 zql zql 4096 2023年 2月 7日 Music
drwxr-xr-x 4 zql zql 4096 10月 6日 16:47 Pictures
drwxr-xr-x 2 zql zql 4096  7月 7日 10:11 Videos
1
zql@zql-PC:~$

注意:当echo $BASH_SUBSHELL的值是0的时候表示没有创建子shell来执行这些命令,如果输出的是1,表示创建了子shell来执行命令。

 zql@zql-PC:~$ (pwd ; ls hallo* ; ll ; echo $BASH_SUBSHELL)
 /home/zql
 hallo.c  hallo.cpp  hallo.java  hallo.md  hallo.py  hallo.sh  hallo.tar  hallo.txt
 总计 40
 -rw-r--r-- 1 zql zql   95 12月28日 20:48 abc
 drwxr-xr-x 3 zql zql 4096 11月 5日 13:17 code
 drwxr-xr-x 2 zql zql 4096 10月 6日 16:43 com.hmja.ccompare
 drwxr-xr-x 2 zql zql 4096 12月28日 19:38 Desktop
 drwxr-xr-x 2 zql zql 4096 10月 9日 18:06 Documents
 drwxr-xr-x 2 zql zql 4096 2023年 2月 7日 Downloads
 drwxr-xr-x 2 zql zql 4096 10月 9日 18:06 gcadlog
 -rw-r--r-- 1 zql zql    0 12月28日 20:57 hallo.c
 -rw-r--r-- 1 zql zql    0 12月28日 20:58 hallo.cpp
 -rw-r--r-- 1 zql zql    0 12月28日 20:57 hallo.java
 -rw-r--r-- 1 zql zql    0 12月28日 20:58 hallo.md
 -rw-r--r-- 1 zql zql    0 12月28日 20:57 hallo.py
 -rw-r--r-- 1 zql zql    0 12月28日 20:57 hallo.sh
 -rw-r--r-- 1 zql zql    0 12月28日 20:58 hallo.tar
 -rw-r--r-- 1 zql zql    0 12月28日 20:58 hallo.txt
 drwxr-xr-x 2 zql zql 4096 2023年 2月 7日 Music
 drwxr-xr-x 4 zql zql 4096 10月 6日 16:47 Pictures
 drwxr-xr-x 2 zql zql 4096  7月 7日 10:11 Videos
 1
 zql@zql-PC:~$

1.8 高效的子shell

1.8.1 后台模式

一种高效的子shell用法就是后台模式。演示后台模式的命令是sleep,睡眠的意思是吧,进程睡眠,该命令在shell脚本中常用于引入一段暂停时间。在命令的末尾加上&就会将命令至于后台模式。

 #将他放置后台30s,使用ps查看当前的进程
 zql@zql-PC:~$ sleep 30&
 [1] 5118
 zql@zql-PC:~$ ps -f
 UID          PID    PPID  C STIME TTY          TIME CMD
 zql         2725    2724  0 20:46 pts/1    00:00:00 -bash
 zql         5118    2725  0 21:02 pts/1    00:00:00 sleep 30
 zql         5128    2725  0 21:03 pts/1    00:00:00 ps -f
 zql@zql-PC:~$ sleep 30&
 [2] 5183
 [1]   已完成               sleep 30
 zql@zql-PC:~$
 
 #可以使用jobs来查看当前的后台信息
 zql@zql-PC:~$ sleep 30&
 [3] 5241
 zql@zql-PC:~$
 zql@zql-PC:~$ jobs
 [2]-  已完成               sleep 30
 [3]+  运行中               sleep 30 &
 zql@zql-PC:~$
 
 #jobs -l可以查看更多的信息
 zql@zql-PC:~$ sleep 30&
 [4] 5266
 zql@zql-PC:~$
 zql@zql-PC:~$ jobs -l
 [3]-  5241 运行中               sleep 30 &
 [4]+  5266 运行中               sleep 30 &
 zql@zql-PC:~$

注意:进入睡眠模式的时候的ID号和ps进程中睡眠模式的ID号是一样的。

将进程列表放置后台

 zql@zql-PC:~$ (sleep 2 ; echo $BASH_SUBSHELL ; sleep 2)&
 [1] 5364
 zql@zql-PC:~$ 1
 
 [1]+  已完成               ( sleep 2; echo $BASH_SUBSHELL; sleep 2 )
 zql@zql-PC:~$

1.8.2 协程

协程就是在后台生成一个子shell,二是在这个子shell里面执行命令。协程的处理需要用到oproc命令,将命令放置后台运行。

 zql@zql-PC:~$ coproc sleep 10
 [1] 5538
 zql@zql-PC:~$
 zql@zql-PC:~$ ps
     PID TTY          TIME CMD
    2725 pts/1    00:00:00 bash
    5538 pts/1    00:00:00 sleep
    5544 pts/1    00:00:00 ps
 zql@zql-PC:~$
 zql@zql-PC:~$
 [1]+  已完成               coproc COPROC sleep 10
 zql@zql-PC:~$

注意:协程是后台在运行,前台也可以进行交互,后台模式是进入了后台,无法再进行交互,除非退出来了或者再后面加上了&加上&就会把命令放入后台,而不会进入后台里面

 zql@zql-PC:~$ coproc sleep 10
 [1] 5630
 zql@zql-PC:~$ jobs
 [1]+  运行中               coproc COPROC sleep 10 &
 zql@zql-PC:~$ jobs -l
 [1]+  5630 运行中               coproc COPROC sleep 10 &
 zql@zql-PC:~$
 [1]+  已完成               coproc COPROC sleep 10
 zql@zql-PC:~$

每次运行的时候,进程ID都是不一样的,但是还可以给进程起名字

 zql@zql-PC:~$ bash
 zql@zql-PC:~$
 zql@zql-PC:~$ coproc myjob1 { sleep 10; } &
 [1] 5734
 zql@zql-PC:~$ jobs
 [1]+  运行中               coproc myjob1 { sleep 10; } &
 zql@zql-PC:~$

当我们进程没有结束的时候开启新的进程的时候,旧的进程依然会运行,直到它结束

 zql@zql-PC:~$ coproc sleep 10
 [1] 5814
 zql@zql-PC:~$ ps
     PID TTY          TIME CMD
    2725 pts/1    00:00:00 bash
    5717 pts/1    00:00:00 bash
    5814 pts/1    00:00:00 sleep
    5822 pts/1    00:00:00 ps
 zql@zql-PC:~$
 zql@zql-PC:~$
 [1]+  已完成               coproc COPROC sleep 10
 zql@zql-PC:~$ coproc sleep 10
 [1] 5925
 zql@zql-PC:~$ coproc sleep 10
 bash: 警告:execute_coproc: 副进程 [5925:COPROC] 仍然存在
 [2] 5928
 zql@zql-PC:~$
结合协程与进程列表

 zql@zql-PC:~$ coproc ( sleep 5 ; sleep 3)
 [1] 6036
 zql@zql-PC:~$
 zql@zql-PC:~$ ps --forest
     PID TTY          TIME CMD
    2725 pts/1    00:00:00 bash
    5717 pts/1    00:00:00  \_ bash
    6036 pts/1    00:00:00      \_ bash
    6048 pts/1    00:00:00      |   \_ sleep
    6050 pts/1    00:00:00      \_ ps
 zql@zql-PC:~$
 zql@zql-PC:~$ ps --forest
     PID TTY          TIME CMD
    2725 pts/1    00:00:00 bash
    5717 pts/1    00:00:00  \_ bash
    6062 pts/1    00:00:00      \_ ps
 [1]+  已完成               coproc COPROC ( sleep 5; sleep 3 )
 zql@zql-PC:~$
 
 #从后面两组信息可以看出,在我们运行协程和进程列表的时候,会再开一个bash子shell,然后再里面运行sleep进程列表,运行完成之后bash子shell会自动关闭,留下一个完成的信息。
 #注意:我是在zsh里面开了子shell bash,所以他会有两个bash,第二个bash才是我们进程协程和进程列表开启的子shell。

1.9 外部命令与内建命令

1.9.1 外部命令

外部命令也叫文件系统命令,是存在bash shell之外的程序,通常位于/bin、/usr/bin、/sbin或/usr/sbin目录中,例如ps就是外部的命令,使用which和type可以找到对应的文件名。

 zql@zql-PC:~$ which ps
 /usr/bin/ps
 zql@zql-PC:~$ which cd
 zql@zql-PC:~$

可以看见ps是外部的命令,而cd则是shell内建命令。

 zql@zql-PC:~$ type pwd
 pwd 是 shell 内建
 zql@zql-PC:~$ type find
 find 是 /usr/bin/find
 zql@zql-PC:~$

find没想到吧他也是外部命令,其实我也没想到。

当执行外部命令的时候就会创建一个子进程,这种操作叫做衍生。

 zql@zql-PC:~$ ps
     PID TTY          TIME CMD
    2725 pts/1    00:00:00 bash
    5717 pts/1    00:00:00 bash
    6201 pts/1    00:00:00 ps
 zql@zql-PC:~$ ps -f
 UID          PID    PPID  C STIME TTY          TIME CMD
 zql         2725    2724  0 20:46 pts/1    00:00:00 -bash
 zql         5717    2725  0 21:07 pts/1    00:00:00 bash
 zql         6208    5717  0 21:10 pts/1    00:00:00 ps -f
 zql@zql-PC:~$

所以你就知道为什么之前查看进程的时候每次都能看到ps,因为他是一个外部的命令,调用的时候会衍生子进程,在子进程里面执行外部命令,注意他们的PID号是不一样的。

当出现进程衍生的时候就会消耗时间和资源来设置新的子进程环境,所以外部命令的开销较高。

1.9.2 内建命令

内建命令与外部命令不同,它们不需要创建子进程来执行,他们和shell编译成了一体,作为shell的组成部分存在。

有些命令既有内建命令也有外部命令,例如pwd和echo。使用type -a即可看见他们所有的路径。

 zql@zql-PC:~$ type -a pwd
 pwd 是 shell 内建
 pwd 是 /usr/bin/pwd
 pwd 是 /bin/pwd
 zql@zql-PC:~$ type -a echo
 echo 是 shell 内建
 echo 是 /usr/bin/echo
 echo 是 /bin/echo
 zql@zql-PC:~$ type -a cd
 cd 是 shell 内建
 zql@zql-PC:~$

可以看见echo与pwd还有别的路径,他们不仅仅是shell内建命令。

注意:which只能看见外部命令

1.9.3 命令别名

查看当前系统可以使用的别名可以使用命令alias

 -a    查看当前所有的可以使用的别名

 # 进入子shell
 zql@zql-PC:~$ bash
 # 查看别名列表
 zql@zql-PC:~$ alias -p
 alias ls='ls --color=auto'
 #退出子shell
 zql@zql-PC:~$ exit
 exit
 #查看别名列表
 zql@zql-PC:~$ alias -p
 alias ll='ls -l'
 alias ls='ls --color=auto'

设置别名

语法

 alias 别名='命令'

 zql@zql-PC:~$ alias l='ls -CF'
 zql@zql-PC:~$ alias la='ls -A'
 zql@zql-PC:~$ alias -p
 alias l='ls -CF'
 alias la='ls -A'
 alias ll='ls -l'
 alias ls='ls --color=auto'
 zql@zql-PC:~$ alias li='ls -i'
 zql@zql-PC:~$ la
 abc                .config         gcadlog     hallo.sh    Music                      .themes
 .bash_history      .deepin-themes  .gtkrc-2.0  hallo.tar   Pictures                   Videos
 .bash_logout       .deepinwine     hallo.c     hallo.txt   .pki                       .vscode
 .bashrc            Desktop         hallo.cpp   .icons      .profile                   .Xauthority
 .cache             .dmrc           hallo.java  .imwheelrc  .Public                    .xsession-errors
 code               Documents       hallo.md    .linglong   .sudo_as_admin_successful  .xsession-errors.old
 com.hmja.ccompare  Downloads       hallo.py    .local      .Templates
 zql@zql-PC:~$ li
 2621458 abc                2622349 Documents  2622032 hallo.cpp   2622002 hallo.sh   2622316 Pictures
 2632317 code               2622348 Downloads  2622031 hallo.java  2622033 hallo.tar  2622350 Videos
 2621748 com.hmja.ccompare  2631954 gcadlog    2622034 hallo.md    2622035 hallo.txt
 2622363 Desktop            2622030 hallo.c    2622024 hallo.py    2622365 Music

注意:被定义的别名仅在当前的shell内有效,他是内建命令。

删除自己定义的别名

语法

 unalias 别名

 zql@zql-PC:~$ unalias li
 zql@zql-PC:~$ li
 -bash: li:未找到命令
 zql@zql-PC:~$

变量(bash)

2.1 变量命名规侧

  • 变量名必须以字母或下划线打头,名字中间只能由字母、数字和下划线组成
  • 变量名的长度不得超过255个字符
  • 变量名在有效的范围内必须是唯一的
  • 在Bash中,变量的默认类型都是字符串型
  • 变量用等号连接值,等号左右两边不能有空格
  • 变量的值如果有空格,需要使用单引号或双引号包括如:“test="hello world!””。其中双引号括起来的内容“$”、“\”和反引号都拥有特殊含义,而单引号括起来的内容都是普通字符。
  • 在变量的值中,可以使用“\”转义符。
  • 如果需要增加变量的值,那么可以进行变量值的叠加。不过变量需要用双引号包含“变量名“或用{变量名}包含变量名。

 a=10,
 a=qbcd

像这样可以变化的参数就是变量,他的值是不定的,可以进行覆盖变化。

2.2 变量的分类(按照存储类型)

  • 字符串型
  • 整型
  • 浮点型
  • 日期型

2.3变量的分类

用户自定义变量

  • 变量自定义的

环境变量

  • 这种变量中主要保存的是和系统操作环境相关的数据。变量可以自定义,但是对系统生效的环境变量名和变量作用是固定的

位置参数变量

  • 这种变量主要是用来向脚本当中传递参数或数据的,变量名不能自定义,变量作用是固定的,(属于预定义变量的一种)

预定义变量

  • 是Bash中已经定义好的变量,变量名不能自定义,变量作用也是固定的
变量分类 名称 作用 内容
用户自定义变量 自定义 自定义 自定义
用户自定义环境变量 自定义 自定义 自定义
系统自带环境变量 确定 确定 自定义
位置参数变量 确定 确定 自定义
预定义变量 确定 确定 自定义

2.4 定义变量

语法

 变量名=值
 变量名="string"

注意:等号之间不能空格,因为在操作系统中使用命令才用空格,如果你定义变量使用了空格,系统会认为是你使用了bash命令。

 zql@zql-PC:~$ x=5
 zql@zql-PC:~$ echo $x
 5
 zql@zql-PC:~$ m1=xyz
 zql@zql-PC:~$ echo m1
 m1
 zql@zql-PC:~$

2.4.1 调用变量

语法

 echo $变量名

注意:Linux系统中,变量的值默认是字符串类型(String)。

 zql@zql-PC:~$ x=5
 zql@zql-PC:~$ y=6
 zql@zql-PC:~$ z=x+y
 zql@zql-PC:~$ echo $z
 x+y
 zql@zql-PC:~$ z=$x+$y
 zql@zql-PC:~$ echo $z
 5+6

2.4.2 变量叠加

语法

 变量名x="$变量名x"叠加的值
 变量名x=${变量名x}叠加的值

 zql@zql-PC:~$ x=123
 zql@zql-PC:~$ x="$x"456
 zql@zql-PC:~$ echo $x
 123456
 zql@zql-PC:~$ x=${x}789
 zql@zql-PC:~$ echo $x
 123456789

2.4.3 变量查看

set 查看所有的变量

直接使用set命令的时候就是查收看所有的变量

选项

 -u    如果设定此选项,调用未声明变量时会报错(默认无任何提示)
 -X  如果设定此选项,在命令执行之前会把命令先输出一次

在shell编程中,不存在的变量和变量值为空的时候调用出来都是空的,为了更好区分二者,使用set -u后不存在的变量就会报错,但是这是临时生效的,

 zql@zql-PC:~$ echo $a
 ​
 ​
 zql@zql-PC:~$ set -u
 zql@zql-PC:~$ echo $a
 -bash: a: 为绑定变量
 zql@zql-PC:~$

2.4.4 变量删除

语法

 unset 变量名

2.5 环境变量

2.5.1 全局环境变量

全局变量对于shell会话和所有生成的子shell都是可见的。

查看全局变量可以使用命令env和printenv

 zql@zql-PC:~$ env
 SHELL=/bin/bash
 LANGUAGE=zh_CN
 XDG_DATA_HOME=/home/zql/.local/share
 XDG_CONFIG_HOME=/home/zql/.config
 PWD=/home/zql
 LOGNAME=zql
 XDG_SESSION_TYPE=tty
 MOTD_SHOWN=pam
 HOME=/home/zql
 LANG=zh_CN.UTF-8
 LS_COLORS=bd=38;5;68;1:ca=38;5;17:cd=38;5;132;1:di=38;5;105:do=38;5;127:ex=38;5;80:pi=38;5;126:fi=38;5;167:ln=38;5;63:mh=38;5;99;1:or=48;5;197;38;5;228;1:ow=38;5;220;1:sg=48;5;234;38;5;100;1:su=38;5;9;1:so=38;5;197:st=38;5;86;48;5;234:tw=48;5;235;38;5;139;3:*LS_COLORS=48;5;89;38;5;197;1;3;4;7:*.BAT=38;5;108:*.ex
 ​
 内容太长--省略--
 ​
 :*.service=38;5;81:*@.service=38;5;45:*.socket=38;5;75:*.device=38;5;24:*.mount=38;5;115:*.automount=38;5;114:*.swap=38;5;113:*.target=38;5;73:*.path=38;5;116:*.timer=38;5;111:*.snapshot=38;5;139:*.desktop=38;5;113:*.crdownload=38;5;38:*.crx=38;5;13:
 SSH_CONNECTION=192.168.8.1 24175 192.168.8.106 22
 LINGLONG_ROOT=/persistent/linglong
 XDG_CACHE_HOME=/home/zql/.cache
 XDG_SESSION_CLASS=user
 TERM=xterm-256color
 USER=zql
 SHLVL=1
 XDG_SESSION_ID=3
 XDG_RUNTIME_DIR=/run/user/1000
 SSH_CLIENT=192.168.8.1 24175 22
 XDG_DATA_DIRS=/persistent/linglong/entries/share:/home/zql/.local/share/linglong/entries/share:/usr/local/share:/usr/share
 PATH=/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/sbin:/usr/sbin
 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus
 SSH_TTY=/dev/pts/1
 _=/usr/bin/env
 OLDPWD=/home
 zql@zql-PC:~$

可以看见二者几乎是一模一样。但是当要查看个别环境变量的时候就只能使用printenv。

 zql@zql-PC:~$ printenv HOME
 /home/zql
 zql@zql-PC:~$ printenv home
 zql@zql-PC:~$ env HOME
 env: "HOME": 没有那个文件或目录
 zql@zql-PC:~$

可以看见查看个别环境变量的时候环境变量必须大写,env也是不能查看的。

查看当前的环境变量

语法

 echo $PATH 


image-20231228212434808.png

2.5.2 局部变量

局部变量只能在定义的进程中可见。

set、printenv、env命令之间的差距很细微,set命令既会显示全局和局部环境变量、用户自定义变量以及局部shell函数,还会按照字母顺序对结果进行排序。与set命令不同,env命令和printenv命令既不会对变量进行排序,也不会输出局部环境变量、局部用户自定义变量以及局部shell函数。在这种情况下,env命令和printenv命令的输出是重复的。不过,env命令有printenv命令不具备的一个功能,这使其略胜一筹。

2.5.3 设置环境变量

语法

 export 变量名=变量值

2.5.4 环境变量与自定义变量的区别

环境变量和用户自定义变量最主要的区别在于,环境变量是全局变量,而用户自定义变量是局部变量。用户自定义变量只在当前的Shellr中生效,而环境变量会在当前Shel和这个Shell的所有子Shell当中生效

变量可以自定义,但是对系统生效的环境变量名和变量作用是固定的

当我们执行脚本的时候就需要指明脚本的路径,绝对路径或者是相对路径,如果向直接使用脚本命令就需要将该文将放入bin目录或者是将该文件目录添加到环境变量中去。

2.5.5 添加PATH变量的值

 PATH="$PATH":/root/sh

2.5.6 常用的环境变量

 HOSTNAME:主机名
 SHELL:当前的shell
 TERM:终端环境
 HISTSIZE:历史命令条数
 SSH_CLIENT:当前操作环境是用ssh连接的,这里记录客户端ip
 SSH_TTY:ssh连接的终端时pts/1
 USER:当前登灵录的用户

2.5.7 PS1环境变量

PS1变量是一种命令提示符设置,可以定义自己喜欢的提示符。

语法

 export PS1=' [\选项 ... \选项] '

注意:目录前面有空格,[ ]外有空格

选项

 \d:显示日期,格式为“星期月日”
 \h:显示简写主机名。如默认主机名“1 ocalhost”
 \H:显示完整的主机名。如默认主机名"'localhost..localdomain”
 \t:显示24小时制时间,格式为“HH:MM:SS”
 \T:显示12小时制时间,格式为“HH:MM:SS”
 \A:显示24小时制时间,格式为“HH:MM'
 \u:显示当前用户名
 \W:显示当前所在目录的完整名称
 \W:显示当前所在目录的最后一个目录
 \$:提示符。如果是r0ot用户会显示提示符为“#”,如果是普通用户会显示提示符为“$”
 \A:显示24小时制时间,格式为“H:MM”
 @:显示l2小时制时间,格式为“HH:MMam/pm”
 \u:显示当前用户名
 \v:显示Bash的版本信息
 \#:执行的第几个命令


image-20231228212612877.png

  • \u就是root用户;
  • @;
  • \h当前的主机名zql;
  • \W当前目录的最后一个目录名称~;
  • $是提示符#

在Linux系统登录是主要生效的环境变量配置文件有以下五个

  • /etc/profile
  • /etc/profile.d/*.sh
  • ~/.bash_profile
  • ~/.bashrc
  • /etc/bashrc

2.5.8 环境变量持久化

对全局环境变量(Linux系统的所有用户都要用到的变量)来说,可能更倾向于将新的或修改过的变量设置放在/etc/profile文件中,但这可不是什么好主意。如果升级了所用的发行版,则该文件也会随之更新,这样一来,所有定制过的变量设置可就都没有了。最好在/etc/profile.d目录中创建一个以.sh结尾的文件。把所有新的或修改过的全局环境变量设置都放在这个文件中。在大多数发行版中,保存个人用户永久性bash shell变量的最佳地点是HOME/.bashrc文件。这适用于所有类型的shell进程。但如果设置了BASH_ENV变量,请记住:除非值为HOME/.bashrc,否则,应该将非交互式shell的用户变量放在别的地方。

注意:图形化界面组成部分(比如GUI客户端)的环境变量可能需要在另外一些配置文件中设置,这和设置bash shell环境变量的文件不一样。

2.5.9 系统语序

locale 设置规则

<语言>_<地区>.<字符集编码><@修正值>

 zh_CN.utf8
 ​
 zh:表示中文
 CN:表示大陆地区
 Utf8:表示字符集
 ​
 de_DE.utf-8@euro
 ​
 de:表示德语
 DE:表示德国
 Utf-8:表示字符集
 euro:表示按照欧洲习惯加以
查询当前系统语系 locale
 LANG:定义系统主语系的变量
 LCALL:定义整体语系的变量

当前所有启动的locale

 LANG=zh_CN.UTF-8
 LC_CTYPE="zh_CN.UTF-8"
 LC_NUMERIC="zh_CN.UTF-8"
 LC_TIME="zh_CN.UTF-8"
 LC_COLLATE="zh_CN.UTF-8"
 LC_MONETARY="zh_CN.UTF-8"
 LC_MESSAGES="zh_CN.UTF-8"
 LC_PAPER="zh_CN.UTF-8"
 LC_NAME="zh_CN.UTF-8"
 LC_ADDRESS="zh_CN.UTF-8"
 LC_TELEPHONE="zh_CN.UTF-8"
 LC_MEASUREMENT="zh_CN.UTF-8"
 LC_IDENTIFICATION="zh_CN.UTF-8"
 LC_ALL=

注意:

 LANG: LANG的优先级是最低的,它是所有LC*变量的默认值,下方所有以LC开头变量(LC_ALL除外)中,        
        如果存在没有设置变量值的变量,那么系统将会使用LANG的变量值来给这个变量进行赋值。
        如果变量有值,则保持不变
 LC_CTYPE:用于字符分类和字符串处理,控制所有字符的处理方式,包括字符编码,
           字符是单字节还是多字节,如何打印等,非常重要的一个变量。
 LC_NUMERIC:用于格式化非货币的数字显示
 LC_TIME:用于格式化时间和日期
 LC_COLLATE:用于比较和排序
 LC_MONETARY:用于格式化货币单位
 LC_MESSAGES:用于控制程序输出时所使用的语言,主要是提示信息,错误信息,
              状态信息,标题,标签,按钮和菜单等
 LC_PAPER:默认纸张尺寸大小
 LC_NAME:姓名书写方式
 LC_ADDRESS:地址书写方式
 LC_TELEPHONE:电话号码书写方式
 LC_MEASUREMENT:度量衡表达方式
 LC_IDENTIFICATION:locale对自身包含信息的概述
 LCALL:它不是环境变量,它是一个宏,它可通过该变量的设置覆盖所有LC变量,
        这个变量设置之后,可以废除LC_的设置值,使得这些变量的设置值与LC_ALL的值一致,
        注意LANG变量不受影响。

优先级:LC*ALL > LC_*> LANG****

查看当前系统语序

 echo $LANG

查看Linux支持的所有语系

 locale -a | more

查看默认语序

 cat /etc/sysconfig/i18n
设置系统的 locale
 #可以修改/etc/profile文件
 #修改/etc/profile文件,在最下面增加
 export LC_ALL=zh_CN.utf8
 export LANG=zh_CN.utf8
 ​
 #命令行中使用命令 source 下配置文件,使其生效
 #修改/etc/locale.gen文件
 #将注释打开即可,修改完成后,执行下 locale-gen 命令使其生效
 #en_SG ISO-8859-1
 en_US.UTF-8 UTF-8
 #en_US ISO-8859-1
 ​
 #命令行模式
 localectl set-locale LANG=en_US.UTF-8
 修改/etc/default/locale
 ​
 #注销一下,使其生效
 LANG=“en_US.UTF-8”
 LANGUAGE=“en_US:en”
 ​
 #创建/etc/locale.conf文件
 LANG=en_AU.UTF-8
 LC_COLLATE=C
 LC_TIME=en_DK.UTF-8
 # 使其生效执行
 source 文件名

2.6 位置参数变量

image-20230713200402610.png

 #!/bin/bash
 ​
 a=$1
 b=$2
 ​
 sum=$(( $a + $b ))
 ​
 echo $sum

注意:

  • $*会把每一个参数看成一个整体
  • $@会把每个参数当成独立的个体
  • 当使用for循环的时候就可以看出二者明显的差距

2.7 预定义变量

image-20230713200519731.png

 zql@zql-PC:~$ echo $$
 2725
 zql@zql-PC:~$ echo $!
 5630
 zql@zql-PC:~$ echo $?
 0
 zql@zql-PC:~$

2.7.1 逻辑&&与||

$$当前面与后面的语句都执行的时候,返回0

||当返回0的之后就是前面的语句执行,否则就是后面的语句执行

2.7.2 接受键盘输入(input) read

语法

 read 选项 变量名

选项

 -p: “提示信息”:在等待read输入时,输出提示信息
 -t: 秒数:read命令会一直等待用户输入,使用此选项可以指定等待时间
 -n: 字符数:read命令只接受指定的字符数,就会执行
 -s: 隐藏输入的数据,适用于机密信息的输入

 #!/bin/bash
 ​
 ​
 #-p: “提示信息”:在等待read输入时,输出提示信息
 #-t: 秒数:read命令会一直等待用户输入,使用此选项可以指定等待时间
 #-n: 字符数:read命令只接受指定的字符数,就会执行
 #-s: 隐藏输入的数据,适用于机密信息的输入
 #read -t 等待用户输入30秒 -p 提示:请你输入一个数字 变量
 read -t 30 -p "请你输入一个数字:" num1
 ​
 read -t 30 -p "请再次输入一个数字" num2
 ​
 sum=$(( $num1 + $num2 ))
 ​
 echo $sum

注意

 脚本开头必须是#!/bin/bash

2.8 声明变量类型

declare

使用declare声明变量类型

语法

 declare [+/-] [选项] 变量名

选项

 -        给变量设定类型属性
 +        取消变量的类型属性
 -a        将变量声明为数组型
 -i        将变量声明为整数型integer
 -r        将变量声明为只读变量,设置后不能修改该变量的值,无法删除变量,也不能修改只读的属性
 -x        将变量声明为环境变量
 -p        显示置顶变量的被声明类型

 zql@zql-PC:~$ a=1
 zql@zql-PC:~$ b=2
 zql@zql-PC:~$ c=$a+$b
 zql@zql-PC:~$ echo $c
 1+2
 zql@zql-PC:~$ declare -i c=$a+$b
 zql@zql-PC:~$ echo $c
 3

输出数组变量类型

通过下标来保存多个数据

 #首先声明数组类型
 zql@zql-PC:~$ declare -a name[0]="zql"
 zql@zql-PC:~$ name[1]="tr"
 zql@zql-PC:~$ name[2]="kgm"
 zql@zql-PC:~$ name[3]="lb"
 zql@zql-PC:~$ echo ${name[*]}
 zql tr kgm lb
 zql@zql-PC:~$ echo ${name[0]}
 zql

2.9 数组变量

环境变量的一个很酷的特性是可以作为数组使用。数组是能够存储多个值的变量。这些值既可以单独引用,也可以作为整体引用

语法

 变量名=(值 值 值...值)

 zql@zql-PC:~$ test=(Java C Python PHP Go)
 zql@zql-PC:~$ echo $test
 Java
 zql@zql-PC:~$ echo ${test[2]}
 Python
 zql@zql-PC:~$ echo ${test[1]}
 C
 zql@zql-PC:~$ echo ${test[0]}
 Java
 zql@zql-PC:~$ echo ${test[*]}
 Java C Python PHP Go
 zql@zql-PC:~$

删除数组

语法

 unset 数组名

 zql@zql-PC:~$ unset test
 zql@zql-PC:~$ echo ${test[*]}
 ​
 zql@zql-PC:~$

Shell运算符

  • 第一种运算方法就是declare数值运算法,但是不推荐使用;
  • 第二种是使用expr命令和let来运算,不推荐使用,运算符前后必须有空格;
  • 第三种是使用**$((运算式))两个小括号阔以换成[]**进行运算,推荐使用

 #第一种运算方法
 zql@zql-PC:~$ a=1
 zql@zql-PC:~$ b=2
 zql@zql-PC:~$ c=$a+$b
 zql@zql-PC:~$ echo $c
 1+2
 zql@zql-PC:~$ declare -i c=$a+$b
 zql@zql-PC:~$ echo $c
 3
 ​
 #第二种运算方法
 zql@zql-PC:~$ d=$(expr $a + $b)
 zql@zql-PC:~$ echo $d
 3
 zql@zql-PC:~$ let e=$a+$b
 zql@zql-PC:~$ echo $e
 3
 zql@zql-PC:~$
 ​
 #第三种运算方法,中间运算符和括号可以没有空格
 zql@zql-PC:~$ aa=11
 zql@zql-PC:~$ bb=22
 zql@zql-PC:~$ cc=$(( $aa + $bb ))
 zql@zql-PC:~$ echo $cc
 33
 zql@zql-PC:~$
 ​
 #混合运算
 zql@zql-PC:~$ a=100
 zql@zql-PC:~$ b=50
 zql@zql-PC:~$ c=45
 zql@zql-PC:~$ value=$[$a * ($b - $c)]
 zql@zql-PC:~$ echo $value
 500
 zql@zql-PC:~$

3.1 运算符的优先级

屏幕截图 2023-01-11 165234.png

3.2 运算方法

例1

 #!/bin/bash
 ​
 #定义变量输出
 values=$(( $1 $2 $3 ))
 #输出值
 echo $values
 -----------------------------------------------------------------------------------------
 root@Hacker:~/sh# count3.sh 1 + 2
 3
 root@Hacker:~/sh# count3.sh 6 / 3
 2
 root@Hacker:~/sh# count3.sh 6 - 3
 3

例2

 #!/bin/bash
 ​
 #输入条件
 read -t 30 -p "Please input num1:" num1
 read -t 30 -p "Please input num2:" num2
 read -n1 -t 30 -p "Please input operato[+-*/]:" oper
 echo -e "\n"
 ​
 #判断符号是否正确
 #利用&&进行逻辑输出,前者正确输出,后者就会输出,输出后就退出
 [ "$oper" == "+" ] && echo "$(( $num1 + $num2 ))" && exit
 [ "$oper" == "-" ] && echo "$(( $num1 - $num2 ))" && exit
 [ "$oper" == "*" ] && echo "$(( $num1 * $num2 ))" && exit
 [ "$oper" == "/" ] && echo "$(( $num1 / $num2 ))" && exit
 ​
 #输入错误的时候
 echo "输如错误或有内容未输入!"
 -----------------------------------------------------------------------------------------
 zql@zql-PC:~$ sudo vim count.sh
 请输入密码:
 验证成功
 zql@zql-PC:~$ sudo chmod +x count.sh
 ​
 --加法--
 zql@zql-PC:~$ ./count.sh
 Please input num1:1
 Please input num2:2
 Please input operato[+-*/]:+
 ​
 3
 --减法--
 zql@zql-PC:~$ ./count.sh
 Please input num1:4
 Please input num2:2
 Please input operato[+-*/]:-
 ​
 2
 --乘法--
 zql@zql-PC:~$ ./count.sh
 Please input num1:1
 Please input num2:3
 Please input operato[+-*/]:*
 ​
 3
 --除法--
 zql@zql-PC:~$ ./count.sh
 Please input num1:6
 Please input num2:3
 Please input operato[+-*/]:/
 ​
 2
 --输入错误或不输入--
 zql@zql-PC:~$ ./count.sh
 Please input num1:2
 Please input num2:2
 Please input operato[+-*/]:
 ​
 ​
 zql@zql-PC:~$
 ​
 输如错误或有内容未输入!
 zql@zql-PC:~$ ./count.sh
 Please input num1:2
 Please input num2:+
 Please input operato[+-*/]:+
 ​
 ./count.sh:行11: 2 + + :语法错误: 需要操作数 (错误符号是 "+ ")
 zql@zql-PC:~$
 ​
 --混合运算--
 zql@zql-PC:~$ a=$(( 4+9*5/3))
 zql@zql-PC:~$ echo $(( (3+5)*4 ))
 32
 zql@zql-PC:~$

--逻辑或--

同为假才假,否则为真,同为0为0,否则为1,两个0才为0,其余为1

 zql@zql-PC:~$ echo $(( 1||1 ))
 1
 zql@zql-PC:~$ echo $(( 1||0 ))
 1
 zql@zql-PC:~$ echo $(( 0||0 ))
 0

--逻辑与--

同为真才真,否则为假,同为1为1,否则为0,两个1才为1,其余为0

 zql@zql-PC:~$ echo $(( 0&&0 ))
 0
 zql@zql-PC:~$ echo $(( 0&&1 ))
 0
 zql@zql-PC:~$echo $(( 1&&1 ))
 1

--按位与--

同为真才真,否则为假,同为1为1,否则为0,两个1才为1,其余为0

 zql@zql-PC:~$ echo $(( 1&1 ))
 1
 zql@zql-PC:~$ echo $(( 1&0 ))
 0
 zql@zql-PC:~$ echo $(( 0&0 ))
 0

--按位或--

两个假才假,否则为真,同为0为0,否则为1,两个0才为0,其余为1

 zql@zql-PC:~$ echo $(( 1|1 ))
 1
 zql@zql-PC:~$echo $(( 1|0 ))
 1
 zql@zql-PC:~$ echo $(( 0|0 ))
 0
 zql@zql-PC:~$ echo $(( 0|1 ))
 1

综上所述,逻辑与和按位与情况一样,反之

3.3 变量测试

变量的测试与内容置换,当我们不知道另外一个变量的时候,通过输出变量转换的式子,通过其中一个变量的值来进行另外一个变量的值的判断

变量测试多在Linux脚本优化的时候使用
屏幕截图 2023-01-11 171357.png

可以通过以下示例来理解表的内容

 #当y不存在的时候
 zql@zql-PC:~$ unset y
 zql@zql-PC:~$ x=${y-2}
 zql@zql-PC:~$ echo $x
 2
 ​
 #当y存在为空的时候
 zql@zql-PC:~$ y=""
 zql@zql-PC:~$ x=${y-2}
 zql@zql-PC:~$ echo $x
 ​
 #当y存在不为空的时候
 zql@zql-PC:~$ y=1
 zql@zql-PC:~$ x=${y-2}
 zql@zql-PC:~$ echo $x
 1

配置文件

4.1 环境变量配置文件

环境变量配置文件中主要是定义对系统操作环境生效的系统默认环境变量,如PATH等。

登录的时候就会启用生效的环境变量由以下五个:

  • /etc/profile
  • /etc/profile.d/*.sh
  • ~/.bash_profile
  • ~/.bashrc
  • /etc/bashrc

4.2 环境变量配置文件的功能

放在etc目录线面的会对所有用户生效,放在~家目录的只会对当前用户生效
屏幕截图 2023-01-12 152307.png

登录Shell

  • ./etc/profile

** /etc/profile文件是系统中默认的bash shell的主启动文件。系统中的每个用户登录时都会执行这个启动文件。**

** etc/profile文件是bash shell默认的主启动文件。只要登录Linux系统,bash就会执行/etc/profile启动文件中的命令。**

 zql@zql-PC:~$ cat /etc/profile
 # /etc/profile: system-wide .profile file for the Bourne shell (sh(1))
 # and Bourne compatible shells (bash(1), ksh(1), ash(1), ...).
 ​
 if [ "$(id -u)" -eq 0 ]; then
   PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
 else
   PATH="/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/sbin:/usr/sbin"
 fi
 export PATH
 ​
 if [ "${PS1-}" ]; then
   if [ "${BASH-}" ] && [ "$BASH" != "/bin/sh" ]; then
     # The file bash.bashrc already sets the default PS1.
     # PS1='\h:\w\$ '
     if [ -f /etc/bash.bashrc ]; then
       . /etc/bash.bashrc
     fi
   else
     if [ "$(id -u)" -eq 0 ]; then
       PS1='# '
     else
       PS1='$ '
     fi
   fi
 fi
 ​
 if [ -d /etc/profile.d ]; then
   for i in /etc/profile.d/*.sh; do
     if [ -r $i ]; then
       . $i
     fi
   done
   unset i
 fi
 zql@zql-PC:~$
  • .$HOME/.bash_profile
  • .$HOME/.bashrc
  • .$HOME/.bash_login
  • .$HOME/.profile
 zql@zql-PC:~$ cat $HOME/.bashrc
 # ~/.bashrc: executed by bash(1) for non-login shells.
 # see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
 # for examples
 ​
 # If not running interactively, don't do anything
 case $- in
     *i*) ;;
       *) return;;
 esac
 ​
 # don't put duplicate lines or lines starting with space in the history.
 # See bash(1) for more options
 HISTCONTROL=ignoreboth
 ​
 # append to the history file, don't overwrite it
 shopt -s histappend
 ​
 # for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
 HISTSIZE=1000
 HISTFILESIZE=2000
 ​
 # check the window size after each command and, if necessary,
 # update the values of LINES and COLUMNS.
 shopt -s checkwinsize
 ​
 # If set, the pattern "**" used in a pathname expansion context will
 # match all files and zero or more directories and subdirectories.
 #shopt -s globstar
 ​
 # make less more friendly for non-text input files, see lesspipe(1)
 #[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
 ​
 # set variable identifying the chroot you work in (used in the prompt below)
 if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
     debian_chroot=$(cat /etc/debian_chroot)
 fi
 ​
 # set a fancy prompt (non-color, unless we know we "want" color)
 case "$TERM" in
     xterm-color|*-256color) color_prompt=yes;;
 esac
 ​
 # uncomment for a colored prompt, if the terminal has the capability; turned
 # off by default to not distract the user: the focus in a terminal window
 # should be on the output of commands, not on the prompt
 #force_color_prompt=yes
 ​
 if [ -n "$force_color_prompt" ]; then
     if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
         # We have color support; assume it's compliant with Ecma-48
         # (ISO/IEC-6429). (Lack of such support is extremely rare, and such
         # a case would tend to support setf rather than setaf.)
         color_prompt=yes
     else
         color_prompt=
     fi
 fi
 ​
 if [ "$color_prompt" = yes ]; then
     PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
 else
     PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
 fi
 unset color_prompt force_color_prompt
 ​
 # If this is an xterm set the title to user@host:dir
 case "$TERM" in
 xterm*|rxvt*)
     PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
     ;;
 *)
     ;;
 esac
 ​
 # enable color support of ls and also add handy aliases
 if [ -x /usr/bin/dircolors ]; then
     test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
     alias ls='ls --color=auto'
     #alias dir='dir --color=auto'
     #alias vdir='vdir --color=auto'
 ​
     #alias grep='grep --color=auto'
     #alias fgrep='fgrep --color=auto'
     #alias egrep='egrep --color=auto'
 fi
 ​
 # colored GCC warnings and errors
 #export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
 ​
 # some more ls aliases
 #alias ll='ls -l'
 #alias la='ls -A'
 #alias l='ls -CF'
 ​
 # Alias definitions.
 # You may want to put all your additions into a separate file like
 # ~/.bash_aliases, instead of adding them here directly.
 # See /usr/share/doc/bash-doc/examples in the bash-doc package.
 ​
 if [ -f ~/.bash_aliases ]; then
     . ~/.bash_aliases
 fi
 ​
 # enable programmable completion features (you don't need to enable
 # this, if it's already enabled in /etc/bash.bashrc and /etc/profile
 # sources /etc/bash.bashrc).
 if ! shopt -oq posix; then
   if [ -f /usr/share/bash-completion/bash_completion ]; then
     . /usr/share/bash-completion/bash_completion
   elif [ -f /etc/bash_completion ]; then
     . /etc/bash_completion
   fi
 fi
 # Set LS_COLORS environment by Deepin
 if [[ ("$TERM" = *256color || "$TERM" = screen* || "$TERM" = xterm* ) && -f /etc/lscolor-256color ]]; then
     eval $(dircolors -b /etc/lscolor-256color)
 else
     eval $(dircolors)
 fi
 zql@zql-PC:~$

/etc/profile的作用

  • USER变量:
  • LOGNAME变量:
  • MAIL变量:
  • PATH变量:
  • HOSTNAME变量:
  • HISTSIZE变量:
  • umask
  • 调用/etc/profile.d/*.sh文件

umask权限

查看系统默认权限

基本访问权限

代表字符 权限 对文件的含义 对目录的含义 八进制值
r 读权限 可以读文件的内容 可以列出目录中的文件列表 4
w 写权限 可以修改该文件 可以在该目录中创建、删除文件 2
x 执行权限 可以执行该文件 可以使用 cd 命令进入该目录 1

文件类型标识符

标识符 类型 标识符 类型
d 代表目录 - 普通文件
l 软链接 b 块设备
c 字符设备 p 命令管道文件
s 套接字文件 -- --

文件权限系统,将操作文件的用户分成三类:

  • 文件的拥有者,即属主 user(u)
  • 文件所属组的成员,即属组 group(g)
  • 其他用户 other(o)

注意

  • 文件最高权限为666(读写)
  • 目录最高权限为777(读写执行)
  • 权限不能使用数字进行换算,而必须使用字母
  • umask定义的权限,是系统默认权限中准备丢弃的权限
 zql@zql-PC:~$ umask
 0022
 zql@zql-PC:~$ ls -l
 总计 44
 -rw-r--r-- 1 zql  zql    95 12月28日 20:48 abc
 drwxr-xr-x 3 zql  zql  4096 11月 5日 13:17 code
 drwxr-xr-x 2 zql  zql  4096 10月 6日 16:43 com.hmja.ccompare
 -rwxr-xr-x 1 root root  523 12月29日 16:07 count.sh
 drwxr-xr-x 2 zql  zql  4096 12月28日 19:38 Desktop
 drwxr-xr-x 2 zql  zql  4096 10月 9日 18:06 Documents
 drwxr-xr-x 2 zql  zql  4096 2023年 2月 7日 Downloads
 drwxr-xr-x 2 zql  zql  4096 10月 9日 18:06 gcadlog
 -rw-r--r-- 1 zql  zql     0 12月28日 20:57 hallo.c
 -rw-r--r-- 1 zql  zql     0 12月28日 20:58 hallo.cpp
 -rw-r--r-- 1 zql  zql     0 12月28日 20:57 hallo.java
 -rw-r--r-- 1 zql  zql     0 12月28日 20:58 hallo.md
 -rw-r--r-- 1 zql  zql     0 12月28日 20:57 hallo.py
 -rw-r--r-- 1 zql  zql     0 12月28日 20:57 hallo.sh
 -rw-r--r-- 1 zql  zql     0 12月28日 20:58 hallo.tar
 -rw-r--r-- 1 zql  zql     0 12月28日 20:58 hallo.txt
 drwxr-xr-x 2 zql  zql  4096 2023年 2月 7日 Music
 drwxr-xr-x 4 zql  zql  4096 10月 6日 16:47 Pictures
 drwxr-xr-x 2 zql  zql  4096  7月 7日 10:11 Videos
 zql@zql-PC:~$

如何计算当前创建的目录的权限

用权限符号来进行计算,所有权限减去默认权限(umask的值022),取消掉相同的权限,留下的就是创建芯目录的权限

 #创建新目录的权限
 drwxrwxrwx    -    -----w--w-    =    drwxr-xr-x(属主读写执行、属组读执行、其他用户读执行)
 #创建新文件的权限
 -rw-rw-rw-    -    -----w--w-    =    -rw-r--r--(属主读写、属组读、其他用户读)

~/.bash_profile的作用

  • 调用了~/.bashrc文件。
  • 在PATH变量后面加入了":$HOME/bin"这个目录

/etc/bashrc的作用

  • PS1变量
  • umask
  • PATH变量
  • 调用/etc/profile.d/*.sh文件

4.3 source

修改配置文件后使用该命令让文件直接生效,直接让脚本生效都可以,.在做命令使用的时候就是source

语法

 ---source 配置文件
 ---. 配置文件

其他配置文件

注销的时候生效的环境变量配置文件

~/.bash_logout

该文件默认是空的,只有当你执行关机的时候进行某种操作才会有内容

~/bash_history

该文件会保存你上次登录终端后使用的历史命令

若要修改历史命令的上限需要在.bashrc和/etc/profile文件中修改

Shell登录信息

本地终端欢迎信息:/etc/issue
屏幕截图 2023-01-12 162814.png

远程终端欢迎信息:/etc/issue.net

转义符在/etc/issue..net文件中不能使用

是否显示此欢迎信息,由ssh的配置文件 /etc/ssh/sshd_config决定,加入 "Banner/etc/issue.net"行才能显示(记得重启SSH服务)

shell正则表达式

5.1 正则表达式

正则表达式是用于描述字符排列和匹配模式的一种语法规则,它主要用于字符串的模式分割、匹配、查找及替换操作。

正则表达式与通配符

正则表达式用来在文件中匹配符合条件的字符串,正则是包含匹配。grep、awk、sed等命令可以支持正则表达式。

通配符用来匹配符合条件的文件名,通配符是完全匹配。s、find、cp这些命令不支持正则表达式,所以只能使用shell自己的通配符来进行匹配了。

通配符

通配符
* 匹配任意长度的任意字符,可以是0个
? 匹配任意单个字符,必须是1个
[ ] 匹配指定字符范围内的任意单个字符
[a-z,A-Z,0-9] 匹配所有数字字母,可以不加逗号
[a-z] 表示a-z,A-Y,表示a,A,b,B.....a。不包含Z
[A-Z] 表示A,b,B.....z,Z。不包含a
[a-Z] 表示所有大小写字母
[:upper:] 所有大写字母
[:lower:] 所有小写字母
[:alpha:] 所有字母,大小写
[:digit:] 所有数字
[:alnum:] 所有数字+字母
[:blank:] 水平空白字符
[:space:] 水平或垂直空白字符
[:punct:] 标点符号
[:print:] 可打印字符
[:cntrl:] 控制(非打印)字符
[:graph:] 图形字符
[:xdigit:] 十六进制字符
[^] 匹配指定字符范围外的任意单个字符
[^0-9] 相当于^[:digit:^]
[^a-z] 表示Z + 其他
[^A-Z] 表示a + 其他

最常用的是前三个

基础正则表达式
屏幕截图 2023-01-12 170108.png

*示例

 zql@zql-PC:~$ mkdir a
 zql@zql-PC:~$ cd a/
 zql@zql-PC:~/a$ touch abc
 zql@zql-PC:~/a$ touch abcd
 zql@zql-PC:~/a$ touch aaa
 zql@zql-PC:~/a$ ls
 aaa  abc  abcd
 zql@zql-PC:~/a$ cd
 zql@zql-PC:~$ find . -name abc
 ./a/abc
 zql@zql-PC:~$ find . -name abc?
 ./a/abcd
 zql@zql-PC:~$ find . -name abc*
 ./a/abcd
 ./a/abc
 ./Pictures/Wallpapers/abc-124.jpg
 ./Pictures/Wallpapers/abc-123.jpg
 ./.vscode/extensions/cweijan.vscode-office-3.1.8/icons/abc.svg

test.txt文本内容如下:
image-20231229162702103.png

 zql@zql-PC:~$ mkdir test
 zql@zql-PC:~$ vim test.txt
 zql@zql-PC:~$ grep "aa*" test.txt
 a
 aa
 aaa
 aaaa
 aaaaa

错误示例

 zql@zql-PC:~$ grep "a*" test.txt
 a
 aa
 aaa
 aaaa
 aaaaa
 b
 bb
 bbb
 bbbb
 bbbbb
 zql@zql-PC:~$

注意:

  • "a*会匹配所有内容,包括空白行
  • "aa*”会匹配至少包含有一个a的行
  • "aaa*"匹配最少包含两个连续a的字符串
  • "aaaaa*"则会匹配最少包含四个个连续的字符串

原因是*本身就是字符匹配,匹配0个或任意个字符,所以会匹配所有的字符

.示例

 zql@zql-PC:~$ cat test.txt
 a
 aa
 aaa
 aaaa
 aaaaa
 ​
 b
 bb
 bbb
 bbbb
 bbbbb
 ​
 Hello
 Helllo
 Hedlo
 Hoooooood
 zql@zql-PC:~$ grep "H..o" test.txt
 Hoooooood
 zql@zql-PC:~$ grep "H...o" test.txt
 Hello
 Hedlo
 Hoooooood
 zql@zql-PC:~$ grep "H.*d" test.txt
 Hedlo
 Hoooooood
 zql@zql-PC:~$ grep "H.*" test.txt
 Hello
 Helllo
 Hedlo
 Hoooooood
 zql@zql-PC:~$

注意:

  • "hear..tail"会匹配头部和尾部之间的两个字符,“.”的数量决定中间匹配多少个字母
  • "hear.*tail"会匹配首尾之间所有的字符

".*"会匹配所有的内容

^与$示例

 zql@zql-PC:~$ grep "^a" test.txt 
 a
 aa
 aaa
 aaaa
 aaaaa
 zql@zql-PC:~$ grep "^H" test.txt 
 Hello
 Helllo
 Hedlo
 Hoooooood
 zql@zql-PC:~$ grep "o$" test.txt 
 Hello
 Helllo
 Hedlo
 zql@zql-PC:~$ grep "b$" test.txt 
 b
 bb
 bbb
 bbbb
 bbbbb
 zql@zql-PC:~$ grep "^$" test.txt 
 ​
 ​
 zql@zql-PC:~$ grep -n "^$" test.txt 
 6:
 12:
 zql@zql-PC:~$ 

注意:

  • "^"匹配行首,"$"匹配行尾
  • "^$"会直接匹配空白行

[]示例

 zql@zql-PC:~$ grep "a[aa]a" test.text 
 aaa
 aaaa
 aaaaa
 zql@zql-PC:~$ grep "[a-z]" test.text 
 a
 aa
 aaa
 aaaa
 aaaaa
 b
 bb
 bbb
 bbbb
 bbbbb
 Hello
 Helllo
 Hedlo
 Hooooooo
 785d
 zql@zql-PC:~$ grep "[0-9]" test.text 
 123
 456
 789
 10
 785d
 zql@zql-PC:~$ grep "^[a-z]" test.text 
 a
 aa
 aaa
 aaaa
 aaaaa
 b
 bb
 bbb
 bbbb
 bbbbbzql@zql-PC:~$ grep "^[a-z]" test.text 
 a
 aa
 aaa
 aaaa
 aaaaa
 b
 bb
 bbb
 bbbb
 bbbbb

注意:

  • "head[mn]tail"会匹配首尾之间中间字母为m或n的字符
  • "[0-9]"会匹配任意一个数字,前面加^就是匹配行首,后面加$就是匹配行尾
  • "[a-z]"会匹配任意一个小写字母,"[A-Z]"会匹配任意一个大写字母
  • "^[a-z]"会匹配开头是小写字母的行,换成大写也可以

当括号[]内外都有^的时候就表示否定的意思,除了括号里面的其他的都要,匹配的是开头行,括号要内的符号就表示取反,外面的符号就表示开头匹配

特别的例子

 [0-9]\{4}-[0-9]\{2\}-[0-9]\{2\}                            #匹配日期格式YYYY-MM-DD
 [0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}.[0-9]\{1,3\)\    #匹配IP地址

扩展正则表达式

屏幕截图 2023-01-16 162820.png

屏幕截图 2023-01-16 163349.png

例:匹配邮箱

[0-9a-zA-Z]+@[0-9a-zA-Z]+(.**[0-9a-zA-Z_]+){1,3}****

 创建邮箱文件
 zql@zql-PC:~$ cat mail.txt 
 [email protected]
 [email protected]
 [email protected]
 [email protected]
 [email protected]
 12.com
 [email protected]
 sc.com
 yama@com
 ​
 匹配邮箱
 zql@zql-PC:~$ grep -E "[0-9a-zA-Z_]+@[0-9a-zA-Z_]+(\.[0-9a-zA-Z_]+){1,3}" mail.txt 
 [email protected]
 [email protected]
 [email protected]
 [email protected]
 [email protected]
 [email protected]

例:匹配IP

^(([0-9].)|(1-9.)|(1**0-9.)|(20-4.)|(25[0-5].)){3}(([0-9])|(1-9)|(10-9)|(20-4)|(25[0-5]))$**

 zql@zql-PC:~$ cat ip.txt 
 192.168.8.8
 111.111.111.111
 999.999.999.999
 255.555.55.555
 174.34.56.78
 ​
 匹配IP
 zql@zql-PC:~$ grep -E "^(([0-9]\.)|([1-9][0-9]\.)|(1[0-9][0-9]\.)|(2[0-4][0-9]\.)|(25[0-5]\.)){3}(([0-9])|([1-9][0-9])|(1[0-9][0-9])|(2[0-4][0-9])|(25[0-5]))$" ip.txt 
 192.168.8.8
 111.111.111.111
 174.34.56.78
 zql@zql-PC:~$ 

5.2 字符截取

printf 格式化输出

语法

 printf(选项)(参数)
 --help:在线帮助;
 --version:显示版本信息。

参数 输出格式:指定数据输出时的格式; 输出字符串:指定要输出的数据。 格式替代符

 %b 相对应的参数被视为含有要被处理的转义序列之字符串。
 %c ASCII字符。显示相对应参数的第一个字符
 %d, %i 十进制整数
 %e, %E, %f 浮点格式
 %g %e或%f转换,看哪一个较短,则删除结尾的零
 %G %E或%f转换,看哪一个较短,则删除结尾的零
 %o 不带正负号的八进制值
 %s 字符串
 %u 不带正负号的十进制值
 %x 不带正负号的十六进制值,使用a至f表示10至15
 %X 不带正负号的十六进制值,使用A至F表示10至15
 %% 字面意义的%

转义序列

 \a 警告字符,通常为ASCII的BEL字符
 \b 后退
 \c 抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略
 \f 换页(formfeed)
 \n 换行
 \r 回车(Carriage return)
 \t 水平制表符
 \v 垂直制表符
 \ 一个字面上的反斜杠字符
 \ddd 表示1到3位数八进制值的字符,仅在格式字符串中有效
 \0ddd 表示1到3位的八进制值字符

例1

 zql@zql-PC:~$ printf
 printf:用法: printf [-v var] 格式 [参数]
 zql@zql-PC:~$ print
 zql@zql-PC:~$ print "123"
 Error: no such file "123"
 zql@zql-PC:~$ printf "123"
 123zql@zql-PC:~$ 

例2

 zql@zql-PC:~$ ls
 grade.txt  ip.txt  mail.txt  student.txt  teat.txt  test.text
 zql@zql-PC:~$ cat grade.txt 
 ID      Name    php     Python  MySQL   Linux
 1       zql     90      90      90      99
 2       tr      90      90      99      90
 3       LIsa    80      80      88      88
 zql@zql-PC:~$ printf '%s\t %s\t %s\t %s\t %s\t %s\t \n' $(cat grade.txt)
 ID       Name    php     Python  MySQL   Linux   
 1        zql     90      90      90      99      
 2        tr      90      90      99      90      
 3        LIsa    80      80      88      88   
 ​
 如果不加上\n就不会换行
 zql@zql-PC:~$ printf '%s\t %s\t %s\t %s\t %s\t %s\t' $(cat grade.txt)
 ID       Name    php     Python  MySQL   Linux  1        zql     90      90      90      99     2        tr      90      90      99       90     3        LIsa    80      80      88      88 
Reply Favorite View the author
All Replies
兆兆嘟嘟嘟
deepin
2023-12-30 04:07
#1

感谢分享。

Reply View the author
天阁创客official
deepin
2023-12-30 04:41
#2

基于deepin的shell编程V0.2.update23.12完整版链接下载:https://www.123pan.com/s/LjEDVv-OFJZ3.html

Reply View the author
静夜思001
deepin
2023-12-30 04:42
#3

like

Reply View the author
nero28
deepin
2023-12-30 17:07
#4

点赞,666

Reply View the author
zjb
deepin
2024-01-01 17:39
#5

非常有用!非常感谢!

Reply View the author