Shell脚本基础—编写脚本会遇到的各种问题_shell不加解释器ps不到

48 阅读4分钟

![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/99cd58d3087f4657a8535d12475be920~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=oQJL8IH8OTwh%2B5iju%2BWFDat56Sw%3D)   
 ![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/cd460d8e70914c5f8a1abdff17ccb25e~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=r9Thd%2BMAEC88P%2FAjHNhiss2cU7g%3D)


#####  一个奇怪的现象:



#!/bin/bash

pwd cd .. pwd


按照上面的思路,上面的执行结果就是:   
 1. 显示当前的路径   
 2. 返回上一层   
 3. 再显示当前的路径(也就是上一层的路径)


![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/ba7cc455ebf148efb74e20f55ff5f51b~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=9iwP%2FVe3ES9c2wDT18ViyLVOHYQ%3D)


 结果:   
 ![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/68f5e30ff91e4fc086627481444d6015~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=0EIO33p58PqGvYxw7W1MQ3tg%2BCE%3D)   
  路径是对的,可是执行之后,并没有返回上一层,这是什么情况?   
    
 下面就来介绍一下内置命令的概念以及Shell脚本执行的过程:


#### 内置命令 &Shell特点 & Shell脚本的执行过程:




---



#####  1. 内置命令:



如上的: cd ..

还有 : export echo


#####  2. Shell特点:



  1. 解释非编译型

  2. 弱类型

  3. 执行模式:交互式/批处理式

    这里的弱类式的意思就是:变量类型不太会说明,不像C语言中有:char int string...


#####  3. Shell脚本的执行过程:



首先,我们都知道: 一个可执行的程序,是二进制,而这里是一个文本,那是怎么运行的?

#!/bin/bash

pwd cd .. pwd

一: 执行:bash ./test1.sh 后的过程 :

  1. 当前进程会fork(),子进程调用exec,然后将#!后面的解释器bash程序的代码替换当前进程

  2. 上面解释器的代码已经替换了子进程,下来就是一一去处理文本中的命令

  3. 子进程再去fork(),让孙子进程去处理第一行的命令

    将第一行命令作为参数传给解释器(当前的解释器就类似于"函数")

  4. 上面只是处理了一行的命令,如果还有命令行,再去fork()

二 :从上面的执行过程,我们就可以知道,为什么会出现上面的奇怪现象?

因为:
    上面的 cd.. 是在 子bash 中处理的,而对 父bash 没有影响

##### 4. 如何处理内置命令这种问题?


不准 父bash 创建子进程处理这个内置命令, 父bash 自己处理



方式一:

  用 . 修饰脚本

方式二:

source 修饰脚本

方式一:


![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/bb80b2d796504566a21bbd9bca4dbbbf~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=yCpUnH2xSLJxBf%2BFMAWcr7YONhw%3D)


方式二:


![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/d43d7dc446e44382b314c2d64a3815ff~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=oTXbqAqiGb6c7SciQShMD4Li138%3D)


#### 赋值和命名规则




---



##### 1. 赋值和命名规则



变量名命名的规则 :

  1. 首个字符必须为字母(a-z 或者 A-Z)

  2. 中间不能有空格,可以使用下划线()

  3. 不能使用标点符号

  4. 不能使用bash中的关键字(可以通过help命令来查看关键字)


##### 2. 使用一个赋过值的变量,给变量前加 $ :


![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/8d488c0539624ef287676b86ed4f8dfd~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=L7Llq1996cRd9qbh48a2B7QYUTo%3D)


vim test2.sh:



#!/bin/bash

myint=22 mychar=c myfloat=3.15 mystring="hello Shell"

echo myintechomyint echo mychar echo myfloatechomyfloat echo mystring


![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/916a0adcf32144d895634abf0ff3a846~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=EC8AoR2lItQV0BbwHkUH2JldYoA%3D)


而如果要实现赋过值的变量和一个字符串拼接,应该在变量名外面加上{ },为了让解释器更好的识别变量边界:


![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/c69cab7b99094835829900f5e984dea6~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=6G0MHbSFI4yQ12YhHimWyQfI2rk%3D)



由上图我们可以看出:

  1. 实现两个赋过值的变量拼接: aab 直接将两个变量拼接在一起

  2. 实现一个赋过值的变量和字符串拼接:

    给变量外边加上花括号{};用来区分边界

  3. 如果不加花括号,则会将变量和紧挨着的字符串一起当做一个新的变量 这样输出的结果就为空


![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/9dc8293b7ade485ba7f51eadd604ae49~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=OjMMiUtocBwWmrnjfVzm5wHtSwc%3D)


##### 3. 只读变量 & 删除变量




---



######  只读变量:使用readonly修饰变量



#!/bin/bash

readonly mystr="hello" echo mystrmystr=worldechomystr mystr=world echo mystr


![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/53fa5591033d4fb5a837b69749369863~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=KtqY8A16fdew6Q89XxZiH29FKt8%3D)


###### 删除变量:使用unset命令


![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/95cb585e83b44c09918ed5a41933925d~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=bP22hnT1VvV%2FHhgt%2BDJmK7fcSKU%3D)   
 而只读变量是不能被删除的!   
 ![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/ef8eb1e4d5ea4129b50f66d9052697d8~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=TkARDk6Xh4ZyhqkIQ5ZAGTvPG1U%3D)


##### 4. 变量类型 :




---



Shell变量是弱类型,而这里的变量类型和C语言的变量类型是不一样的



  1. 本地变量

    简单的来说:本地变量就好比是C语言中的局部变量
    只在当前的Shell实例中有效,其他的程序无效

  2. 环境变量

类似于C语言中的全局变量 在所有的程序中都有效 命令:export 环境变量

  1. Shell变量

    意思就是Shell脚本中的变量 有两种 :本地变量 环境变量


下面通过例子来证明:   
 ![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/93b85d0cc0b144bf9a00736c860e8457~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=qfQRbYjW9jww%2FWcuAzV1mCSBK7Q%3D)


##### 5. 获取字符串的长度 & 提取子字符串 :


![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/f907330aab074f629de6346a82df0f3c~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=15QnT748OrK%2Fd7kacvJwUZzzKKc%3D)



#!/bin/bash

mystring=abcde12345

echo ${#mystring} # 获取字符串的长度

echo {mystring:1:4} # 从字符串第2个字符开始截取4个字符 echo {mystring:2:5} # 从字符串第3个字符开始截取5个字符 [root@localhost Shell]# bash test5.sh 10 bcde cde12

  1. ${#变量名} : 表示获取变量的字符串长度

  2. mystring:2:5{mystring:2:5} {mystring:1:4}: 表示从某个字符开始(下标)截取5个或者4个字符
    (后面的表示字符的个数而不是结束位置的下标)


##### 6. 通配符 :



    • :匹配0个或多个任意字符
  1. ? : 匹配一个任意字符
  2. :匹配一个方括号中的任意一个字符的一次出现

下面通过实例来解释上的意思:


##### 1. \*


![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/604d784bf1274aa2aa4073ac9eddca7e~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=LzcZSFT9CX3Vk1D9KjMB4HUBu1c%3D)


##### 2. [ ]


![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/86b6a85058e143d69463c0f8a37e9f04~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=x4HGdz1wRaIJSpgJX1cRPNUA0Ww%3D)


##### 3. ?


![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/1c3727aaca9a497ea00873bb95393296~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=EcEgNwhO%2FgmvyPcR1PvPneHpNqg%3D)


##### 4. [ ]?


![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/42dfc2a076a9451d98da30a29685dafe~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=SPfYK8fbO%2BnUVEuZJaAR1ju5i%2FM%3D)


##### 5. 删除所有带file的文件:


![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/c6005d9f114c4398a4a6cf8a42306381~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=iIqWu3uBFWEVx7ZmC5I1kjn4p0o%3D)


#### 命令代换和算术代换




---


##### 1. 命令代换 :



两种方式:

1. 用反引号``将命令括起来

   注意:内容其实也是一条命令
        ``反引号不要写成单引号

2. 用$()将命令括起来

Shell先执行该条命令,再去将输出结果立刻代换到当前的命令行中


代码解释:


![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/b4c55cc3d2654771a177633689377276~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=TA13%2F6YifUnBseq6UFOv2ZInEg4%3D)


![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/f806e86955d94f11bf9f605dadd57aa3~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=BzPAWYi27ZG%2FDuDIMLkFgkOEU1U%3D)


##### 2. 算术运算:



常用的算术运算符: (()) 双括号

而这个只能用做+-*/% <<和()的运算符,并且只能进行整数运算


代码解释:   
 ![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/a379a5825d5c4868b36905c6e815816f~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=jNMy89GAX7b9TSXgBJSglnZ8%2FCI%3D)


![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/a1a3359d1ab548019f085d08297feb16~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=unFWDnpllavS2BfmaFgTU%2BOmB94%3D)


错误:   
 ![这里写图片描述](https://p6-xtjj-sign.byteimg.com/tos-cn-i-73owjymdk6/bc6c11855fa64a57b7b530d9b3372893~tplv-73owjymdk6-jj-mark-v1:0:0:0:0:5o6Y6YeR5oqA5pyv56S-5Yy6IEAg5L2c6ICFdmlwMTAyNGPkuqTmtYE=:q75.awebp?rk3s=f64ab15b&x-expires=1772818509&x-signature=ZAXsMWL%2Fp0qiLkkmfugjuYB2tD0%3D)


#### 转义字符




---



和C语言相似,将\当做转义字符(\还可以被当成续行)

另外:如果文件名带有-(横杠)的话,用上面的转义字符 \ 是不行的

 两种方式解决:

 1. touch -- -file1
 2. touch -- ./-file.bck

#### 单引号和双引号的区别




---



C语言中:

   1. 单引号 '':用来界定字符的
   2. 双引号 "":用来界定字符串的

而Shell中,两者都是用来界定字符串的界定符

两者的区别就是:

  1. 单引号 '':将单引号的字符串按照原样输出,不做任何转换
  2. 双引号 "": 会将字符串中的转义字符·反引号都会被当做命令执行

下面通过例子来解释:



#!/bin/bash