文件的格式及执行

文件格式

文件第一行标识需要用什么语言执行脚本。文件以 .sh 结尾,如test.sh

  1. #! /bin/bash

文件执行

修改执行权限后执行

  1. #修改文件权限
  2. chmod +x test.sh

然后在当前文件的绝对路径下,执行 ./test.sh

使用source执行

不用修改执行权限,直接执行。要保证在当前文件的绝对路径下

  1. source ./test.sh

使用bash执行

bash执行文件,会开启个新的进程

  1. bash ./test.sh

单引号 双引号 反引号

关于变量

  1. #! /bin/bash
  2. url="shenshuai89@qq.com"
  3. #单引号不会转化变量,把内容作为完整字符串输出
  4. website1='shell:${url}'
  5. #双引号可以把内部的变量进行转化
  6. #使用双引号包围变量,可以 使变量内的空白以及换行都能正确显示
  7. website2="shell:${url}"
  8. #单引号输出 shell:${url}
  9. echo $website1
  10. #双引号输出 shell:shenshuai89@qq.com
  11. echo $website2
  12. # 反引号内放的是linux命令,会把命令执行的结果作为字符串打印出来
  13. `linux命令`
  14. [root@VM-0-11-centos code]# params=`ls`
  15. [root@VM-0-11-centos code]# echo $params
  16. dockerDemo nodeapi

定义变量和取消变量

  1. name="123"
  2. echo ${name}
  3. # 输出:123
  4. unset name
  5. echo ${name}
  6. #

shell变量面试题

  1. [root@VM-0-11-centos shell]# echo user1=`whoami` > who.sh
  2. [root@VM-0-11-centos shell]# echo $user1
  3. [root@VM-0-11-centos shell]# source who.sh
  4. [root@VM-0-11-centos shell]# echo $user1
  5. root
  6. [root@VM-0-11-centos shell]# sh
  7. sh-4.2# echo $user1
  8. sh-4.2#
  • 每次调用bash都会开启一个子shell,不保留当前shell变量。
  • 调用source是在当前shell环境加载脚本,因此会保留变量

    关于格式

    ```bash

    使用双引号包围变量,可以使变量内的空白以及换行都能正确显示

所有结果整行输出,不进行换行

echo $(ls -l)

结果会做格式化显示,有空格和换行

echo “$(ls -l)”

  1. 字符串可以由单引号' '包围,也可以由双引号" "包围,也可以不用引号。它们之间是有区别<br />三种形式的区别:<br />1) 由单引号' '包围的字符串:
  2. - 任何字符都会原样输出,在其中使用变量是无效的。
  3. - 字符串中不能出现单引号,即使对单引号进行转义也不行。
  4. <br />2) 由双引号" "包围的字符串:
  5. - 如果其中包含了某个变量,那么该变量会被解析(得到该变量的值),而不是原样输出。
  6. - 字符串中可以出现双引号,只要它被转义了就行。
  7. <br />3) 不被引号包围的字符串
  8. - 不被引号包围的字符串中出现变量时也会被解析,这一点和双引号" "包围的字符串一样。
  9. - 字符串中不能出现空格,否则空格后边的字符串会作为其他变量或者命令解析。
  10. ```bash
  11. #!/bin/bash
  12. n=66
  13. str1=shenshuai89@qq.com$n str2="shell \"script\" $n"
  14. str3='中文网 $n'
  15. echo $str1
  16. echo $str2
  17. echo $str3
  18. #输出结果
  19. # shenshuai89@qq.com66
  20. # shell "script" 66
  21. # 中文网 $n

str1 中包含了$n,它被解析为变量 n 的引用。$n后边有空格,紧随空格的是 str2;Shell 将 str2 解释为一个新的变量名,而不是作为字符串 str1 的一部分。

str2 中包含了引号,但是被转义了(由反斜杠\开头的表示转义字符)。str2 中也包含了$n,它也被解析为变量 n 的引用。

str3 中也包含了$n,但是仅仅是作为普通字符,并没有解析为变量 n 的引用。

特殊符号

$$ 当前 Shell 进程 PID
$0 当前脚本的绝对路径+文件名
$1 第一个参数
$2 第二个参数
$# 传递给脚本或函数的参数个数。
$@ 传递给脚本或函数的所有参数。
$* 传递给脚本或函数的所有参数。
$? 表示上一个命令的退出状态,或者上一个函数的返回值
  1. function get() {
  2. echo "Process ID: $$"
  3. echo "File Name: $0"
  4. echo "First Parameter : $1"
  5. echo "Second Parameter : $2"
  6. echo "All parameters 1: $@"
  7. echo "All parameters 2: $*"
  8. echo "Total: $#"
  9. }
  10. get js shell

$?上个命令的退出状态

  1. if [ "$1" == 100 ]
  2. then
  3. exit 0
  4. else
  5. exit 1
  6. fi

需要使用bash开启新进程测试,否则会退出

  1. #测试
  2. bash ./return.sh
  3. echo $?
  4. # 输出1
  5. bash ./return.sh 100
  6. echo $?
  7. # 输出1

$?函数的返回值

  1. function add() {
  2. return $(($1+$2))
  3. }
  4. add 11 24
  5. echo $?

字符串

子串操作

  1. mingyan=goodgoodstudy,daydayup!
  2. ${变量} 返回变量值
  3. ${#变量} 返回变量长度
  4. ${变量:start} 返回变量start数值之后的字符,且包含start位置的字符
  5. ${变量:start:length} 提取start之后的 [length长度]的字符,
  6. ${变量#word} 从变量开头删除最短匹配的word子串 ${mingyan:good}
  7. ${变量##word} 从变量开头删除最长匹配的word子串
  8. ${变量%word} 从变量结尾删除最短的word
  9. ${变量%%word} 从变量结尾开始删除最长匹配的word
  10. #替换操作
  11. ${变量/pattern/string} string代替第一个匹配的pattern
  12. ${变量//pattern/string} 用string代替所有的pattern
  1. mingyan="goodgoodstudy,daydayup!"
  2. shuai@shuais-MacBook-Pro batchRename % echo ${mingyan}
  3. goodgoodstudy,daydayup!
  4. shuai@shuais-MacBook-Pro batchRename % echo ${#mingyan}
  5. 23
  6. shuai@shuais-MacBook-Pro batchRename % echo ${mingyan:4}
  7. goodstudy,daydayup!
  8. shuai@shuais-MacBook-Pro batchRename % echo ${mingyan:4:9}
  9. goodstudy
  10. shuai@shuais-MacBook-Pro batchRename % echo ${mingyan#good}
  11. goodstudy,daydayup!
  12. shuai@shuais-MacBook-Pro batchRename % echo ${mingyan##good}
  13. goodstudy,daydayup!
  14. shuai@shuais-MacBook-Pro batchRename % echo ${mingyan##study}
  15. goodgoodstudy,daydayup!
  16. shuai@shuais-MacBook-Pro batchRename % echo ${mingyan##goodgoodstudy}
  17. ,daydayup!
  18. shuai@shuais-MacBook-Pro batchRename % echo ${mingyan%up!}
  19. goodgoodstudy,dayday
  20. shuai@shuais-MacBook-Pro batchRename % echo ${mingyan/good/hao}
  21. haogoodstudy,daydayup!
  22. shuai@shuais-MacBook-Pro batchRename % echo ${mingyan//good/hao}
  23. haohaostudy,daydayup!

获取字符串的长度

string-name,#加字符串变量名

  1. #!/bin/bash
  2. str="shenshuai89@qq.com"
  3. echo ${#str}

字符串拼接合并

Shell 中你不需要使用任何运算符,将两个字符串并排放在一起就能实现拼接

  1. #!/bin/bash
  2. email="shenshuai89@qq.com"
  3. username="北鸟南游"
  4. str1=$username$email #中间不能有空格
  5. str2="$username $email" #如果被双引号包围,那么中间可以有空格
  6. str3=$username": "$email #中间可以出现别的字符串
  7. str4="$username: $email" #这样写也可以
  8. str5="${username}Script: ${email}index.html" #这个时候需要给变量名加上大括号
  9. echo $str1
  10. echo $str2
  11. echo $str3
  12. echo $str4
  13. echo $str5

字符串截取

从指定位置开始截取

这种方式需要两个参数:除了指定起始位置,还需要截取长度${string: start :length},length 是要截取的长度(省略的话表示直到字符串的末尾)

  1. #!/bin/bash
  2. email="shenshuai89@qq.com"
  3. echo ${email: 4: 7}
  4. # 输出shuai89

从右侧开始计数

从字符串的右边开始计数${string: 0-start :length},从右侧计数,要从1开始

  1. #!/bin/bash
  2. email="shenshuai89@qq.com"
  3. echo ${email: 0-14: 7}

从指定字符(子字符串)开始截取

这种截取方式无法指定字符串长度,只能从指定字符(子字符串)截取到字符串末尾。Shell 可以截取指定字符(子字符串)右边的所有字符,也可以截取左边的所有字符。

  • 使用 # 号截取右边字符 ${string#*chars}
  • 使用 号截取右边字符 ${string%chars}
    1. #! /bin/bash
    2. email="shenshuai89@qq.com"
    3. echo ${email#*shuai}
    4. echo ${email%shuai*}
    5. # 89@qq.com
    6. # shen
    如果有多个符号条件,希望直到最后一个指定字符(子字符串)再匹配结束,那么可以使用##或者**
    1. #! /bin/bash
    2. email="shenshuai89@qq.com"
    3. echo ${email#*sh}
    4. echo ${email##*sh}
    5. # enshuai89@qq.com
    6. # uai89@qq.com

    数组

    定义数组,使用()

    Shell 中,用括号( )来表示数组,数组元素之间用空格来分隔 ```bash

    !/bin/bash

    arr=(1 2 3) echo “${arr[2]}”

Shell 是弱类型的,它并不要求所有数组元素的类型必须相同

arr=(23 34 ‘defineArray’) echo “${arr[2]}”

  1. ⚠️注意:赋值号=两边不能有空格,必须紧挨着数组名和数组元素
  2. <a name="JOCR4"></a>
  3. ### 数组增加元素
  4. shell定义的数组长度是不固定的,定义之后还可以增加元素。
  5. ```bash
  6. #!/bin/bash
  7. # 给数组增加元素
  8. names=('sam' 'shenshuai')
  9. names[2]='beiniaonanyou'
  10. echo ${names[2]}
  11. # 获取数组中的所有元素${arr[*]}
  12. echo ${names[*]}
  13. # 获取数组长度 ${#arr[*]}
  14. echo ${#names[*]}

数组拼接

将两个数组连接成一个数组,利用@或*,将数组扩展成列表,然后再合并到一起

  1. #!/bin/bash
  2. arr1=(1 3 5)
  3. arr2=('string' 'number')
  4. arrAll=(${arr1[*]} ${arr2[*]})
  5. echo ${arrAll[*]}

删除数组元素

shell使用 unset 关键字来删除数组元素 unset array_name[index]

  1. #!/bin/bash
  2. unset arrAll[2]
  3. echo ${arrAll[*]}
  4. # 删除数组全部
  5. unset arrAll
  6. echo ${arrAll[*]}

使用set可以查看系统的所有变量

read获取输入

read用来从标准输入中读取数据并赋值给变量。默认就是从键盘读取用户输入的数据;
语法: read [options] [values]

-p prompt 显示提示信息,提示内容为 prompt。
-r 原样读取(Raw mode),不把反斜杠字符解释为转义字符
-s 静默模式(Silent mode),不会在屏幕上显示输入的字符。当输入密码和其它确认信息的时候,这是很有必要的
-n num 读取 num 个字符,而不是整行字符。
  1. #!/bin/bash
  2. read -p "input your name age > " name age
  3. echo "名字:$name"
  4. echo "年龄:$age"

运算

有(())、let、expr等计算方式

(())

双小括号 (( )) 是 Bash Shell 中专门用来进行整数运算的命令,它的效率很高,
((表达式)):将数学运算表达式放在(())中

  1. echo $((1+1))
  2. echo $((2-1))
  3. echo $((2*2))
  4. echo $((2/1))
  5. echo $((8<3))

let

let的作用和(())类似,都是对数据进行运算。
两者都是只能处理整数,不能处理小数或字符串。

  1. a=10 b=20
  2. let c=a+b
  3. echo c

expr

expr运算,数字和运算符号中间要有空格,否则会被当作字符串输出。
乘号*要做转义处理

  1. #!/bin/bash
  2. # 两个数字运算,中间要留空格,否则会当作完整字符串输出
  3. expr 1 + 1 #2
  4. expr 5 - 2 #3
  5. expr 2 \* 7 #14
  6. expr 5 / 2 #2

条件语句

if else

  1. read a
  2. read b
  3. if (($a == $b))
  4. then
  5. echo "a==b"
  6. else
  7. echo "a!=b"
  8. fi

if elif else

  1. echo 'input age number'
  2. read age
  3. if (($age <=2));then echo '婴儿';
  4. elif (($age >=3 && $age <=8 )); then
  5. echo '幼儿';
  6. elif (($age >=9 && $age <=17)); then
  7. echo '少年';
  8. elif (( $age >=18 && $age <= 25))
  9. then echo '成年'
  10. elif (( $age >= 26 && $age <= 40))
  11. then echo '青年'
  12. elif (($age>=41 && $age <=60))
  13. then echo '中年'
  14. else
  15. echo '老年'
  16. fi
  1. printf 'input integer number: '
  2. read num
  3. if (($num == 1)); then echo 'Monday';
  4. elif (($num ==2));then echo 'Tuesday';
  5. elif (($num ==3));then echo 'Wednesday';
  6. elif (($num ==4));then echo 'Thursday';
  7. elif (($num==5)); then echo 'Friday';
  8. elif (($num==6)); then echo 'Saturday';
  9. elif (($num==7)); then echo 'Sunday';
  10. else 'error';
  11. fi

case

  1. printf "input integer number: "
  2. read num
  3. case $num in
  4. 1)
  5. echo "Monday";;
  6. 2)
  7. echo "Tuesday";;
  8. 3)
  9. echo "Wednesday";;
  10. 4)
  11. echo "Thursday";;
  12. 5)
  13. echo "Friday";;
  14. 6)
  15. echo "Saturday";;
  16. 7)
  17. echo "Sunday";;
  18. *)
  19. echo "error"
  20. esac

while

  1. i=1
  2. sum=0
  3. while ((i<=100))
  4. do
  5. ((sum += i))
  6. ((i++))
  7. done
  8. echo "result: $sum"
  1. sum=0
  2. echo "请输入您要计算的数字,按 Ctrl+D 组合键结束读取"
  3. while read n
  4. do
  5. ((sum += n))
  6. done
  7. echo "sum result: $sum"

for

  1. sum=0
  2. for ((i=0; i<=100; i++))
  3. do
  4. ((sum += i))
  5. done
  6. echo "result sum: $sum"

break continue

break

使用 while、until、for、select 循环时,如果想提前结束循环,可以使用 break 或者 continue 关键字。

  1. #!/bin/bash
  2. sum=0
  3. while read n; do
  4. if ((n>0));then
  5. ((sum+=n))
  6. else
  7. break
  8. fi
  9. done
  10. echo "sum is $sum

Shell 中的 break 和 continue 能够跳出多层循环;break n或者continue n,默认跳出当前循环

  1. #!/bin/bash
  2. i=0
  3. while ((++i)); do
  4. j=0
  5. while ((++j)); do
  6. if ((i>4)); then
  7. break 2
  8. fi
  9. if ((j>4));then
  10. break
  11. fi
  12. printf "%-4d" $((i*j))
  13. done
  14. printf "\n"
  15. done

第7行表示跳出2层循环;

break 用来结束所有循环,循环语句不再有执行的机会;continue 用来结束本次循环,直接跳到下一次循环,如果循环条件成立,还会继续循环。

continue

跳出当前循环,100以内的值相加,使用ctrl+d结束

  1. #!/bin/bash
  2. sum=0
  3. while read n; do
  4. if ((n<1 || n>100)); then
  5. continue
  6. fi
  7. ((sum+=n))
  8. done
  9. echo "sum=$sum"

不跳出循环

printf中 %d 的意思是按照整数格式输出后面的第一个参数的值。 printf中 %-4d的意思:输出一个int型数,4位宽度,左对齐。后面若还有输出项时,n的输出至少占4位,不足4位时,后面补空格到4位;若超过4位时,按实际宽度输出n的值。

  1. #!/bin/bash
  2. for ((i=1; i<=9; i++)); do
  3. for ((j=1; j<=9; j++)); do
  4. printf "%d*%d=%-4d" $i $j $((i*j))
  5. done
  6. printf "\n"
  7. done
  1. 1*1=1 1*2=2 1*3=3 1*4=4 1*5=5 1*6=6 1*7=7 1*8=8 1*9=9
  2. 2*1=2 2*2=4 2*3=6 2*4=8 2*5=10 2*6=12 2*7=14 2*8=16 2*9=18
  3. 3*1=3 3*2=6 3*3=9 3*4=12 3*5=15 3*6=18 3*7=21 3*8=24 3*9=27
  4. 4*1=4 4*2=8 4*3=12 4*4=16 4*5=20 4*6=24 4*7=28 4*8=32 4*9=36
  5. 5*1=5 5*2=10 5*3=15 5*4=20 5*5=25 5*6=30 5*7=35 5*8=40 5*9=45
  6. 6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36 6*7=42 6*8=48 6*9=54
  7. 7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49 7*8=56 7*9=63
  8. 8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64 8*9=72
  9. 9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81

条件添加,退出多层循环

  1. for ((i=1; i<=9; i++)); do
  2. for ((j=1; j<=9; j++)); do
  3. if ((i<j)); then
  4. printf "\n"
  5. continue 2
  6. fi
  7. printf "%d*%d=%-4d" $i $j $((i*j))
  8. done
  9. printf "\n"
  10. done
  1. 1*1=1
  2. 2*1=2 2*2=4
  3. 3*1=3 3*2=6 3*3=9
  4. 4*1=4 4*2=8 4*3=12 4*4=16
  5. 5*1=5 5*2=10 5*3=15 5*4=20 5*5=25
  6. 6*1=6 6*2=12 6*3=18 6*4=24 6*5=30 6*6=36
  7. 7*1=7 7*2=14 7*3=21 7*4=28 7*5=35 7*6=42 7*7=49
  8. 8*1=8 8*2=16 8*3=24 8*4=32 8*5=40 8*6=48 8*7=56 8*8=64
  9. 9*1=9 9*2=18 9*3=27 9*4=36 9*5=45 9*6=54 9*7=63 9*8=72 9*9=81

select in

select in是增强交互,可以将in后的值按照编号显示输出。用户选择不同的编号,执行不同的操作。
select in 是 Shell 独有的一种循环,非常适合终端(Terminal)这样的交互场景。

  1. #!/bin/bash
  2. echo "What is your favourite OS?"
  3. select name in "Linux" "Windows" "Mac OS" "UNIX" "Android"
  4. do
  5. echo $name
  6. done
  7. echo "You have selected $name"

⚠️注意,select 是无限循环(死循环),输入空值,或者输入的值无效,都不会结束循环,只有遇到 break 语句,或者按下 Ctrl+D 组合键才能结束循环。
select in通常和case in一起使用,用户选择不同序号执行不同程序。

  1. echo "which is your love os?"
  2. select name in "Linux" "windows" "mac" "unix" "android"
  3. do
  4. case $name in
  5. "Linux")
  6. echo "Linux是一个类UNIX操作系统,它开源免费,运行在各种服务器设备和嵌入式设备。"
  7. break;;
  8. "windows")
  9. echo "Windows是微软开发的个人电脑操作系统,它是闭源收费的。"
  10. break;;
  11. "mac")
  12. echo "Mac OS是苹果公司基于UNIX开发的一款图形界面操作系统,只能运行与苹果提供的硬件之上。"
  13. break;;
  14. "unix")
  15. echo "UNIX是操作系统的开山鼻祖,现在已经逐渐退出历史舞台,只应用在特殊场合。"
  16. break;;
  17. "android")
  18. echo "Android是由Google开发的手机操作系统,目前已经占据了70%的市场份额。"
  19. break;;
  20. *)
  21. echo "输入错误,请重新输入"
  22. esac
  23. done
  24. echo "you have selected $name"

函数

Shell 函数的本质是一段可以重复使用的脚本代码,使用时直接调用即可。
shell函数语法

  1. function name() {
  2. statements
  3. [return value]
  4. }

定义一个函数,计算所有参数的和

  1. #!/bin/bash
  2. function getsum(){
  3. local sum=0
  4. for n in $*
  5. do
  6. ((sum+=n))
  7. done
  8. return $sum
  9. }
  10. getsum 10 20 30
  11. echo $?

$*表示所有参数,$?表示函数的退出状态(返回值)

参考文档:
c语言编程
http://c.biancheng.net/view/706.html
阿里云课堂
https://edu.aliyun.com/course/155/lesson/list?utm_content=m_1000297219
shell编程范例
https://tinylab-1.gitbook.io/shellbook/01-chapter1