Linux_Shell
一、Shell 种类与归属
- Unix与Linux常见的Shell脚本解释器有bash,sh,csh,ksh等(PS: bash 完全兼容sh)
- bash : linux 默认的shell
- sh : unix 默认的shell
- csh : 是linux中比较大的内核,命令指向/bin/tcsh的,可以认为csh为tcsh
- ksh : 兼容商业发行版
2. shell 本身是用C语言编写的程序,它是用户操作unix/linux的桥梁,用户的大部分工作是通过shell来完成的
shell 既是一种命令语言,也是一种程序设计语言,他有自己的编程结构,变量,参数和很多高级语言中的控制语句与循环语句
shell 两种交互: ① 交互型:用户输入一条,shell就执行一条 ② 批处理:用户写多条命令存在于一个shell脚本中,shell一次性完成
二、Shell 与其他语言区别
- shell 是一种解释性语言(运行时编译),而C、C++、Java 等高级语言是编译型语言(程序运行前,预编译)
- shell 相对于其他高级语言对文件处理更为方便快捷,但是运行的效率不如编译后的高级语言
三、不建议使用 Shell 场景
- 资源密集型的任务,尤其在需要考虑效率时(比如,排序,hash等等)。
- 需要处理大任务的数学操作,尤其是浮点运算,精确运算,或者复杂的算术运算(这种情况一般使用C++或FORTRAN 来处理)。
- 有跨平台(操作系统)移植需求(一般使用C 或Java)。
- 复杂的应用,在必须使用结构化编程的时候(需要变量的类型检查,函数原型,等等)。
- 对于影响系统全局性的关键任务应用。
- 对于安全有很高要求的任务,比如你需要一个健壮的系统来防止入侵、破解、恶意破坏等等。
- 项目由连串的依赖的各个部分组成。
- 需要大规模的文件操作。
- 需要多维数组的支持。
- 需要数据结构的支持,比如链表或数等数据结构。
- 需要产生或操作图形化界面 GUI。
- 需要直接操作系统硬件。
- 需要 I/O 或socket 接口。
- 需要使用库或者遗留下来的老代码的接口。
- 私人的、闭源的应用(shell 脚本把代码就放在文本文件中,全世界都能看到)。
四、简单 Shell 示例
1 2 3 4 5 6 7 8 9 10 11 12 13 | [root@hadoop09 - linux tmp] # cat firstShell.sh # .sh 是shell文件类型 #!/bin/bash # bash文件头 #!作为约定标记,告诉系统需要什么解释器运行 # Description: shell simple example # # 简述该shell文件功能作用,这里输出一句话 echo welcom to use shell # shell执行命令 [root@hadoop09 - linux tmp] # sh firstShell.sh # 使用sh命令执行shell welcom to use shell [root@hadoop09 - linux tmp] # ll # 查看shell运行权限 total 4 - rw - r - - r - - . 1 root root 76 Sep 7 18 : 22 firstShell.sh # 可以看到所有用户组都没有运行权限 [root@hadoop09 - linux tmp] # chmod a+x firstShell.sh # 赋予权限 [root@hadoop09 - linux tmp] # ./firstShell.sh # ./执行shell welcom to use shell # 输出结果 |
再看一个例子:
功能:让用户选择Y 或N,如果使用者输入n 或N 时,就显示“Oh,interrupt”,如果不是Y/y/N/n 之内的其他字节,就显示“I don't know what your choice is”
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | [root@hadoop09 - linux tmp] # cat secondShell.sh #!/bin/bash #------------------------------------------------ #当运行一个脚本的时候,这个脚本会让用户选择Y 或N , #如果使用者输入Y 或y 时,就显示“OK,continue” #如果使用者输入n 或N 时,就显示“Oh,interrupt” #如果不是Y/y/N/n 之内的其他字节,就显示“I don't know what your choice is” #------------------------------------------------ echo "please input Y/y or N/n" read words if [ "$words" = "Y" - o "$words" = "y" ];then echo "OK,continue" elif [ "$words" = "N" - o "$words" = "n" ];then echo "Oh,interrupt" else echo "I don't know what your choice is" fi [root@hadoop09 - linux tmp] # sh secondShell.sh please input Y / y or N / n y OK, continue [root@hadoop09 - linux tmp] # sh secondShell.sh please input Y / y or N / n n Oh,interrupt [root@hadoop09 - linux tmp] # sh secondShell.sh please input Y / y or N / n a I don't know what your choice is |
五、Shell 注释
shell 中没有多行注释,需要注释时只需在行首加上#
六、Shell 变量
变量类型
- 局部变量:局部变量在脚本或命令中定义,仅在当前shell实例中有效,其他shell启动的程序不能访问局部变量
- 环境变量:所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候shell脚本也可以定义环境变量
- shell变量:shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行
- 特殊变量:$0;$1,$2,$3...$9;$#;$*;$@;$?;$$
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | [root@hadoop09 - linux tmp] # cat thirdShell.sh #!/bin/bash #Description...# num = 6 # 定义变量,有点像javascript echo "num:$num" # 没加{},{}可加可不加 num = 8 # 重新给变量赋值,前面赋值将被覆盖 echo "num:${num}" # 加上{} 有时解释器会解释成 "num:$num" 加上花括号是为了方便系统识别变量边界,为变量加上{}是个好习惯 unset num # 删除变量 echo "num:${num}" [root@hadoop09 - linux tmp] # sh thirdShell.sh num: 6 num: 8 num: # 删除变量后,变量为空 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [root@hadoop09 - linux tmp] # cat fourthShell.sh #!/bin/bash echo "File Name: $0" # $0 当前shell文件名 echo "First Parameter : $1" # $1 shell文件后跟的第一个参数 echo "First Parameter : $2" # $2 shell文件后跟的第二个参数 echo "Quoted Values: $@" # $@ 传递给shell的所有参数,参数作为最小单位输出 echo "Quoted Values: $*" # $* 传递给shell的所有参数 与$@有细微不同,参数作为整体输出 echo "Total Number of Parameters : $#" # $# 传递给shell的参数个数 echo "result : $?" # $? 上一个执行的命令结果-->0:成功;1:失败 有时一些命令返回其它值,表示不同类型的错误 echo "shell pid : $$" # $$ 当前shell进程ID [root@hadoop09 - linux tmp] # sh fourthShell.sh num1 num2 File Name: fourthShell.sh First Parameter : num1 First Parameter : num2 Quoted Values: num1 num2 Quoted Values: num1 num2 Total Number of Parameters : 2 result : 0 shell pid : 3055 |
七、Shell 替换
- 特殊字符替换:使用 -e 替换字符串中的转移字符:\\(反斜杠);\a(警报);\b(退格键);\f(翻页);\n(换行);\r(换行);\t(水平制表符tab);\v(垂直制表符)
- 命令替换:预先执行命令 `command`(反引号)
- 变量替换:类似java三元运算符,或sql中替换函数,例 ${var:-word}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | [root@hadoop09 - linux tmp] # cat fifthShell.sh #!/bin/bash num = 10 echo "this num is ${num} \n" # 未加 -e 转义,将输出原本模样 echo - e "this num is ${num} \n" # 将\n转义,将换行 Date = `date` # 预先执行date命令,将结果赋给Date echo "this date is ${Date}" str = "string" echo "this str is ${str}" # str原本模样 echo "this str is ${str:+" newString "}" # 表示str如果存在,则将newString替换输出 unset str # 删除变量str echo "this str is ${str:-" newString "}" # 表示str如果不存在或为空,则将newString替换输出 echo "this str is ${str:?" str is empty "}" # 表示str如果不存在或为空,则报错,shell停止,报错内容为替换内容 [root@hadoop09 - linux tmp] # sh fifthShell.sh this num is 10 \n this num is 10 this date is Wed Sep 7 19 : 48 : 16 PDT 2016 this str is string this str is newString this str is newString fifthShell.sh: line 13 : str : str is empty |
八、Shell 运算符 (PS: if [] 中 [ ... ] 与 test ... 作用一样)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 算数运算符 (最常使用运算工具:expr 2 + 2 ;注意运算时空格一定要有) num = `expr 2 + 2 ` num = `expr 4 - 2 ` num = `expr 4 \ * 2 ` # 乘法需要加\转义 num = `expr 4 / 2 ` num = 'expr 4 % 2' num = $num1 if [ $num1 = = $num2 ] if [ $num1 ! = $num2 ] 关系运算符 if [ $str1 - eq $str2 ] # 是否相等 if [ $str1 - ne $str2 ] # 是否不相等 if [ $str1 - gt $str2 ] # 是否大于> if [ $str1 - lt $str2 ] # 是否小于< if [ $str1 - ge $str2 ] # 是否大于等于>= if [ $str1 - le $str2 ] # 是否小于等于<= 布尔运算符 if [ $str1 ! = $str2 ] # !非运算 if [ $str1 - eq $str2 - a $str3 - eq $str4 ] # -a and if [ $str1 - eq $str2 - o $str3 - eq $str4 ] # -o or 字符串运算符 if [ $str1 = $str2 ] # 判断两个字符串是否相等 if [ $str1 ! = $str2 ] # 判断两个字符串是否不相等 if [ - z $str1 ] # 判断字符串长度是否为零,为0则true if [ - n $str1 ] # 判断字符串长度是否不为零,不为0则true if [ $str1 ] # 判断字符串是否不为空,不为空则true 文件测试运算符 if [ - r $ file ] # 文件是否可读 if [ - w $ file ] # 文件是否可写 if [ - x $ file ] # 文件是否可执行 if [ - f $ file ] # 是否是普通文件 if [ - d $ file ] # 是否是目录目录文件 if [ - b $ file ] # 是否是块设备文件 if [ - c $ file ] # 是否是字符设备文件 if [ - s $ file ] # 文件是否有内容 if [ - e $ file ] # 文件(包括各类型文件)是否存在 |
九、Shell 数据
- 字符串
- 单引号
- 单引号内$无效,原文本输出
- 单引号内不能再出现单引号
- 双引号
- 双引号内可以有变量
- 可以出现转义字符
- 双引号内可以再次出现双引号
- 拼接字符串
- "words"$str
- "words$str"
- "words,"$str""
- "words,${str}"
- 获取字符串长度
- ${#str}
- 提取字符串
- ${str:1:4}
- 查找字符串
- str="hello linux"
- echo `expr index "${str}" ll` # 注意其中的双引号不能去掉
- 单引号
- 数组
- 定义数组
- arrays=(v1 v2 v3 v4 v5) # 以空格分隔
- arrays[0]=v1 # 也可以单个赋值
- 读取数组
- $arrays/${arrays} # 默认读取第一个值
- ${arrays[n]} # 读取第n+1个值
- ${arrays[*]}/${arrays[@]} # 读取数组中所有值
- 获取数组长度
- ${#arrays[n]} # 读取单个值的长度
- ${#arrays[*]}/${#arrays[@]} # 读取整个数组长度
- 定义数组
十、Shell echo与printf命令
1 2 3 4 5 6 7 8 9 10 11 12 | echo 显示转义字符 # "\"words...\"" 显示变量 显示换行 # 转义换行需要加 -e 显示不换行 # 转义不换行需要加 -e 显示结果重定向到文件 # "words..." > file 注:file若不存在则新建并录入 原样输出 # 使用单引号原样输出 显示命令执行结果 # echo `date` printf 格式化输出,是echo的增强版,类似C语言中的printf 需要注意的是:printf并不会自动换行,需要自行加上\n 格式:printf format - string data printf "%s %s \n" kk ll mm # 每隔一个单词格式化一次%s 代表一个单词,和awk命令中的print有些区别,awk有自己的格式化方式 |
十一、Shell if else 语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | if [ expression ] then Statement(s) to be executed if expression is true fi if [ expression ];then Statement(s) to be executed if expression is true fi if [ expression ];then Statement(s) to be executed if expression is true else Statement(s) to be executed if expression is false fi if [ expression ];then Statement(s) to be executed if expression is true elif [ expression2 ];then Statement(s) to be executed if expression2 is true else Statement(s) to be executed if expression1 and expression2 all false fi |
十二、Shell while 语句
1 2 3 4 | while command do Statement(s) to be executed if command is true done |
十三、Shell until 循环
1 2 3 4 | until command # 与while 判断正好相反 do Statement(s) to be executed until command is true done |
十四、Shell for 循环
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | for 变量 in 列表 do command1 command2 ... commandN done <br> # 示例1 : 遍历1~5,并输出 for loop in 1 2 3 4 5 do echo "The value is: $loop" done <br> # 示例2 : 遍历当前用户家目录下的所有以.bash开头的文件 for FILE in $HOME / .bash * do echo $ FILE done |
十五、Shell case 语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | case 值 in 模式 1 ) command1 command2 command3 ;; 模式 2 ) command1 command2 command3 ;; * ) command1 command2 command3 ;; esac # 示例1 echo 'Input a number between 1 to 4' echo 'Your number is:\c' read aNum case $aNum in 1 ) echo 'You select 1' ;; 2 ) echo 'You select 2' ;; 3 ) echo 'You select 3' ;; 4 ) echo 'You select 4' ;; * ) echo 'You do not select a number between 1 to 4' ;; esac # 示例2 option = "${1}" case ${option} in - f) FILE = "${2}" echo "File name is $FILE" ;; - d) DIR = "${2}" echo "Dir name is $DIR" ;; * ) echo "`basename ${0}`:usage: [-f file] | [-d directory]" exit 1 # Command to come out of the program with status 1 ;; esac |
十七、Shell 跳出循环
1. break 允许跳出所有循环
1 2 3 4 5 6 7 8 9 10 11 12 13 | #!/bin/bash while : do echo - n "Input a number between 1 to 5: " read aNum case $aNum in 1 | 2 | 3 | 4 | 5 ) echo "Your number is $aNum!" ;; * ) echo "You do not select a number between 1 to 5, game is over!" break ;; esac done |
PS:break n 表示跳出第n层循环
1 2 3 4 5 6 7 8 9 10 11 12 13 | #!/bin/bash for var1 in 1 2 3 do for var2 in 0 5 do if [ $var1 - eq 2 - a $var2 - eq 0 ] then break 2 else echo "$var1 $var2" fi done done |
2.continue 允许跳出当前循环体
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | #!/bin/bash while : do echo - n "Input a number between 1 to 5: " read aNum case $aNum in 1 | 2 | 3 | 4 | 5 ) echo "Your number is $aNum!" ;; * ) echo "You do not select a number between 1 to 5!" continue echo "Game is over!" ;; esac done |
运行发现echo "Game is over" 永远不会被执行
同break一样,continue后面跟一个数字表示跳出第几层循环
1 2 3 4 5 6 7 8 9 10 11 12 | #!/bin/bash NUMS = "1 2 3 4 5 6 7" for NUM in $NUMS do Q = `expr $NUM % 2 ` if [ $Q - eq 0 ] then echo "Number is an even number!!-" $NUM continue 2 fi echo "Found odd number" done |
十八、Shell 函数/函数参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | function_name () { list of commands [ return value ] } # 或 function function_name () { list of commands [ return value ] } # 示例1 Hello () { #方法定义 echo "Url is http://xxx/xxx/" } Hello #方法调用,必须先定义方法 # 示例2 带return funWithReturn(){ echo "The function is to get the sum of two numbers..." echo - n "Input first number: " read aNum echo - n "Input another number: " read anotherNum echo "The two numbers are $aNum and $anotherNum !" return $(($aNum + $anotherNum)) } funWithReturn # Capture value returnd by last command ret = $? echo "The sum of two numbers is $ret !" # 示例3 嵌套 number_one () { echo "Url_1 is http://xxx/xxx/" number_two } number_two () { echo "Url_2 is http://xxx/xxx/" } number_one |
删除方法定义
1 | $unset .f function_name |
函数传参
1 2 3 4 5 6 7 8 9 10 11 | #!/bin/bash funWithParam(){ echo "The value of the first parameter is $1 !" # 1 echo "The value of the second parameter is $2 !" # 2 echo "The value of the tenth parameter is $10 !" # 10 echo "The value of the tenth parameter is ${10} !" # 34 echo "The value of the eleventh parameter is ${11} !" # 73 echo "The amount of the parameters is $# !" # 参数个数 12 echo "The string of the parameters is $* !" # 传递给函数的所有参数 1 2 3 4 5 6 7 8 9 34 73 } funWithParam 1 2 3 4 5 6 7 8 9 34 73 |
十九、Shell 输入输出重定向
1. 输出重定向
1 2 3 4 5 6 7 8 9 10 11 12 13 | $ command > file # 示例 $ who > users # 文件不存在则新建,存在则覆盖 $ command >> file # 示例 $ echo line 2 >> users # 文件不存在则新建,存在则追加 $ cat users line 1 line 2 $ |
2. 输入重定向
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | $ command < file # 示例 $ wc - l < users 2 $ $ command << delimiter document delimiter # 示例1 $wc - l << EOF This is a simple lookup program for good ( and bad) restaurants in Cape Town. EOF 3 $ # 示例2 cat << EOF This is a simple lookup program for good ( and bad) restaurants in Cape Town. EOF # 示例3 filename = test.txt vi $filename <<EndOfCommands i This file was created automatically from a shell script ^[ ZZ EndOfCommands |
如果执行某个命令,却不想让结果输出来,可以重定向到/dev/null
1 | $ command > / dev / null |
二十、Shell 文件包含
像其他语言一样,shell中也可以包含外部脚本
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | . filename #或 source filename # 示例1 # 脚本1 1.sh 不必有执行权限 #!/bin/bash url = "http://xxx/xxx/xxx.html" #脚本2 2.sh 必须有执行权限 #!/bin/bash . . / 1.sh echo $url |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步