Day58 Linux shell编程 shell语法 脚本语言

目录

1 shell编程

1.1 概述

1.2执行脚本 

2. shell语法 

2.1shell环境变量

 2.2临时变量

2.3 文件名代换

3. 脚本语法

3.1 条件测试

3.2分支

if/then/elif/fi


1 shell编程

1.1 概述

Shell linux 中一个重要的层次,它是用户与系统交互作用的界面。在介绍 linux 命令时, shell 都作为命 令解释程序出现:它接收用户打入的命令,进行分析,创建子进程实现命令所规定的功能,等子进程终 止工作后,发出提示符。这是shell 最常见的使用方式。
Shell 除了作为命令解释程序以外,还是一种高级程序设计语言, 它有变量,关键字,有各种控制语句, if case while for 等语句,有自己的语法结构 。利用 shell 程序设计语言可以编写出功能很强、但代码简单的程序,特别是它把相关的linux 命令有机地组合在一起,可大大提高编程的效率,充分利用linux系统的开放性能,设计出适合自己要求的命令。
用户在命令行输入命令后,一般情况下 Shell fork exec 该命令,但是 Shell 的内建命令例外,执行内建命令相当于调用Shell 进程中的一个函数,并不创建新的进程。以前学过的 cd. alias. umask exit 等命令即是内建命令,凡是用which 命令查不到程序文件所在位置的命令都是内建命令,内建命令没有单独的man手册,要在 man 手册中查看内建命令,应该执行。
user02$ man bash-builtins

1.2执行脚本 

编写一个简单的脚本 test.sh:
#!/bin/bash
#This is to show what a example looks like
date
echo "Our first example."
echo #this inserts an empty line in output .
echo "We are currently in the following diractory."
echo
/bin/pwd
echo
echo "This diractory contains following files"
/bin/ls
Shell 脚本中用 # 表示注释,相当于 C 语言的 // 注释。但如果 # 位于第一行开头,并且是 #! ( 称为 Shebang) 则例外,它表示该脚本使用后面指定的解释器/bin/sh 解释执行。如果把这个脚本文件加上可执行权限然后执行:
user02@vir:~ $ chmod a + x test.sh
user02@vir:~ $ ./test.sh # 方法一
user02@vir:~ $ . test.sh # 方法二
user02@vir:~ $ source test.sh # 方法三
#source 或者 . 命令是 Shell 的内建命令,这种方式也不会创建子 Shell, 而是直接在交互式 Shell 下逐行执行脚本中的命令
原理: Shell fork 一个子进程并调用 exec 执行 ./test.sh 这个程序 ,exec 系统调用应该把子进程的代码段替换成./test.sh 程序的代码段,并从它的 start 开始执行。然而 test.sh 是个文本文件,根本没有代码段和start 函数,怎么办呢 ?
特例:用 bash 程序直接执行文件时,不需要脚本文件有可执行权限

 user02$ /bin/bash ./test.sh

如果将命令行下输入的命令用 () 括号括起来,那么也会 fork 出一个子 Shell 执行小括号中的命令,一行中可以输入由分号;隔开的多个命令,比如:
user02 $ (cd ..; ls -l ) # 不会改变工作目录

则有不同的效果,cd ..命令是直接在交互式Shell下执行的,改变交互式ShellPWD

user02 $ cd ..; ls -l # 会改变工作目录

2. shell语法 

Shell 变量名通常是以 字母或下划线打头的字母、数字和下划线字符序列,并且大小写字母意义不同
有两种类型的 Shell 变量:环境变量和临时变量

2.1shell环境变量

环境变量可以从父进程传给子进程,因此 Shell 进程的环境变量可以从当前 Shell 进程传给 fork 出来的子进程。用printenv 命令可以显示当前 Shell 进程的环境变量。

 2.2临时变量

只存在于当前 Shell 进程,用 set 命令可以显示当前 Shell 进程中定义的所有变量 ( 包括临时变量和环境变量) 和函数。
环境变量是任何进程都有的概念,而临时变量是 Shell 特有的概念。在 Shell 中,环境变量和临时变量的定义和用法相似。在Shell 中定义或赋值一个变量 :
user02$ VARNAME=HELLO #定义一个临时变量
user02$ export VARNAME=HELLO #定义一个环境变量
user02$ env | grep VARNAME #env能查到就是环境变量,查不到就是临时变量
user02$ unset VARNAME #取消环境变量
注意
  • 等号两边都不能有空格,否则会被Shell解释成命令和命令行参数
注意
  • 在定义变量时不用“VAR” 取变量值时要用。和C语言不同的是,Shell 变量不需要明确定义类型,事实上Shell变量的值都是字符串,比如我们定义VAR=45,其实VAR的值是字符串45而非整数。Shell 变量不需要先定义后使用,如果对一个没有定义的变量取值,则值为空字符串

2.3 文件名代换

这些用于匹配的字符称为通配符 (wildcard), : * ? [ ] 具体如下 :
* :匹配 0 个或多个任意字符
? :匹配一个任意字符
[ 若干字符 ]: 匹配方括号中任意一个字符的次出现一次的文件名         
注意
  • Globbing 所匹配的文件名是由Shell 展开的,也就是说在参数还没传给程序之前已经展开了,比如上述Is ch0[012].doc命令,如果当前目录下有cho00.docch02.doc,则传给Is命令的参数实际上是这两个文件名,而不是一个匹配字符串

命令代换

“ ' ” 反引号括起来的也是一条命令, Shell 先执行该命令,然后将输出结果立刻代换到当前命令行中。
例如 . 定义一个变量存放 date 命令的输出 :
user02 $ DATE = `date`
user02 $ echo = $DATE #$ 变量名:变量的值

命令代换也可以用S()表示:

user02$ DATE=$(date)  

算数代换

使用$(()),用于算术计算,(())中的 Shell变量取值将转换成整数,同样含义的$[ ]等价例如:

user02$ VAR=45
user02$ echo $(($VAR+3)) # 等价 $((VAR+3)) $[VAR+3]

 

S(())) 中只能用 +-*/ () 运算符,并且只能做整数运算
S[base#n], 其中 base 表示进制, n 按照 base 进制解释,后面再有运算数,按十进制解释

 user02$ echo $[2#10+3] #二进制10,然后+3

user02$ echo $[8#10+3] # 八进制 10 ,然后 +3

 转移字符

C 语言类似, \ Shell 中被用作转义字符,用于去除紧跟其后的单个字符的特殊意义 ( 回车除外 ) ,换句话说,紧跟其后的字符取字面值。例如:

 user02$ echo \$PATH

user02$ \\

创建文件 --test

touch --test #报错  

因为各种 UNIX 命令都把 - 号开头的命令行参数当作命令的选项,而不会当作文件名。如果非要处理以号开头的文件名,可以有两种办法:
user02$ touch -- --test
user02$ touch ./--test
\ 还有一种用法,在 \ 后敲回车表示续行, Shell 并不会立刻执行命令,而是把光标移到下一行,给出一
个续行提示符 > ,等待用户继续输入,最后把所有的续行接到一起当作 - 一个命令执行。例如 :
user02$ ls \ # 按回车续行继续输入
> -l # 按回车代表结束

单引号

Shell 脚本中的单引号和双引号一样都是字符串的界定符,而不是字符的界定符。单引号用于保持引号内所有字符的字面值,即使引号内的\ 和回车也不例外,但是字符串中不能出现单引号。如果引号没有配对就输入回车,Shell 会给出续行提示符,要求用户把引号配上对。例如 :
user02$ echo "abcde"
user02$ echo 'abcd'

双引号

被双引号括住的内容,将被视为单一字串。它防止通配符扩展,但允许变量扩展。单引号不能展开变量。

 user02$ VAR=`date`

user02$ echo "$VAR"
2022 09 17 日星期六 10:22:52 CST
user02$ echo "${VAR}"
2022 09 17 日星期六 10:22:52 CST
user02$ echo 'VAR'
user02$ echo '${VAR}'

3. 脚本语法

3.1 条件测试

命令 test [ 可以测试一个条件是否成立,如果测试结果为真,则该命令的 Exit Status 0 ,如果测试结果为假,则命令的Exit Status 1 。例如测试两个数的大小关系 :
user02$ VAR=2
user02$ test $var -gt 1
user02$ echo $?
虽然看起来很奇怪,但左方括号 [ 确实是一个命令的名字,传给命令的各参数之间应该用空格隔开,比如:$VAR -gt 3 ] [ 命令的四个参数,它们之间必须用空格隔开。命令 test [ 的参数形式是相同的,只不过test 命令不需要 ] 参数。以 [ 命令为例,常见的测试命令如下表所示 :
[ -d DIR ] 如果 DIR 存在并且是一个目录则为真
[ -f FILE ] 如果 FILE 存在且是一个普通文件则为真
[ -z STRING ] 如果 STRING 的长度为零则为真
[ -n STRING ] 如果 STRING 的长度非零则为真
[ STRING1 = STRING2 ] 如果两个字符串相同则为真
[ STRING1 ! = STRING2 ] 如果字符串不相同则为真
[ ARG1 OP ARG2 ] ARG1 ARG2 应该是整数或者取值为整数的变量, op -eq ( 等于 ) -ne ( 不等于 ) - lt ( 小于 ) -le ( 小于等于 ) -gt ( 大于 ) -ge ( 大于等于 ) 之中的一个。

C语言类似,测试条件之间还可以做与、或、非逻辑运算:

[ ! EXPR ] EXPR 可以是上表中的任意一种测试条件, ! 表示 逻辑反 ( )”
[ EXPR1 -a EXPR2 ] EXPR1 EXPR2 可以是上表中的任意一种测试条件, -a 表示 逻辑与
[ EXPR1 -o EXPR2 ] EXPR1 EXPR2 可以是上表中的任意一种测试条件, -o 表示 逻辑或

例程:

$ VAR=abc
$ [ -d user02 -a $VAR = 'abc' ]
$ echo $?
注意
如果上例中的 $VAR 变量事先没有定义,则被 Shell 展开为空字符串,会造成测试条件的语法错误
( 展开为 [ -d user02 -a = 'abc' ]) 作为一种好的 Shell 编程习惯,应该总是把变量取值放在双引号之
( 展开为 [ -d user02 -a " " = 'abc' ]):

 $ VAR=abc

$ [ -d user02 -a "$VAR" = 'abc' ]
$ echo $?

3.2分支

if/then/elif/fi

C 语言类似,在 Shell 中用 if then elif else fi 这几条命令实现分支控制。这种流程控制语句本质上也是由若干条Shell 命令组成的
if [ -f ~/.bashrc ] ; then
        . ~/.bashrc
fi

 “==:==”是一个特殊的命令,称为空命令,该命令不做任何事,但Exit Status总是真。

echo "Is it morning? Please answer yes or no. "
read YES_OR_NO
if [ "$YES_OR_NO" = "yes" ]; then
echo "Good morning!"
elif [ "$YES_OR_NO" = "no" ]; then
echo "Good afternoon!"
else
echo "Sorry, $YES_OR_NO not recognized. Enter yes or no."
return ;
fi
上例中的 read 命令的作用是等待用户输入一行字符串,将该字符串存到一个 Shell 变中。
此外, Shell 还提供了 && || 语法,和 C 语言类似,具有 Short-circuit 特性,很多 Shell 脚本喜欢写成这样:

 test "$(whoami)" != 'root' && (echo you are using a non-privileged account;)

&& 相当于 “if...then..." || 相当于 “if not...then..."
&& || 用于连接两个命令,而上面讲的 -a -o 仅用于在测试表达式中连接两个测试条件,要注意它们的区别,例如:

 test "$VAR" -gt 1 -a "$VAR" -lt 3

例程:

#! /bin/bash
echo " 请输入你要判别的文件名 : "
read file_ name
if [ -f " $file_ name" ]; then
        echo 'it is a file
elif [ -d " $file_ nane" ]; then
        echo 'It is a dir'
elif [ -p $file_ _name ] ; then
        echo 'It is pipe
else
        echo 'it is not a known file'
        exit 1
fi

 

 case/esac

case 命令可类比 C 语言的 switch/case 语句, esac 表示 case 语句块的结束。 C 语言的 case 只能匹配整型或 字符型常量表达式,而Shell 脚本的 case 可以匹配字符串和 Wildcard , 每个匹配分支可以有若干条命令, 末尾必须以 ;; 结束 ,执行时找到第一个匹配的分支并执行相应的命令,然后直接跳到 esac 之后,不需要像C 语言一样用 break 跳出
#! /bin/bash
echo "Is it morning? Please answer yes or no."
read YES_OR_NO
case "$YES_OR_NO" in
yes|y|Yes|YES)
echo "Good Morning!";;
[nN][oO])
echo "Good Afternoon!";;
*)
echo "Sorry, $YES_OR_NO not recognized. Enter yes or no."
return 1;;
esac
启动 nfs-kernel-server 服务的命令是:
$ sudo /etc/init.d/nfs-kernel-server start

$1是一个特殊变量,在执行脚本时自动取值为第一个命令行参数,也就是start,所以进入start)分支执行相关的命令。同理,命令行参数指定为stopreload restart 可以进入其它分支执行停止服务、重新加载配置文件或重新启动服务的相关命令

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

慕容离875

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值