简介
Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。
Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。

业界所说的 shell 通常都是指 shell 脚本,Shell 脚本(shell script),是一种为 shell 编写的脚本程序。
shell种类很多,包括sh、bash、xsh、ksh,其中bash是大多数Linux系统默认的shell,下面也将以bash为例。
简单的shell脚本如下:
echo "hello world!" |
运行shell脚本的两种方式:
- 作为可执行程序
chmod +x ./test.sh #赋予权限 ./test.sh #执行脚本 #注意,一定要写成 ./test.sh,而不是 test.sh,即告诉编译器在当前目录执行test.sh!
- 作为解释器参数
/bin/sh test.sh
这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。
变量
命名
变量命名时需要注意变量名和等号之间不能有空格,这点和其它编程语言都不一样。
显式赋值:
var=123
|
隐式赋值:
for file in `ls /etc` 或 for file in $(ls /etc) |
使用
使用一个定义过的变量,只要在变量名前面加美元符号即可!
var=123 echo $var echo ${var} |
变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:
for skill in Ada Coffe Action Java; do echo "I am good at ${skill}Script" done |
如果不给skill变量加花括号,写成echo "I am good at $skillScript"
,解释器就会把$skillScript
当成一个变量(其值为空),代码执行结果就不是我们期望的样子了。
推荐给所有变量加上花括号,这是个好的编程习惯。
readonly
使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变。
var=123 echo ${var} readonly var var=456 echo ${var} |
删除
使用 unset 命令可以删除变量。
变量被删除后不能再次使用。unset 命令不能删除只读变量。
类型
shell存在三种变量类型:
- 局部变量:局部变量在脚本或命令中定义,仅在当前shell实例中有效。
- 环境变量:所有的程序,包括shell启动的程序,都能访问环境变量。
- shell变量:由shell程序设置的特殊变量,包括局部变量和全局变量。
字符串
定义
字符串可以用单引号,也可以用双引号,也可以不用引号。
- 单引号里的任何字符都回原样输出;单引号字符串中的单引号必须成对出现。
- 双引号里可以出现变量和转义字符。
name='bob' str='this is $name' echo ${str} str="this is $name" echo ${str} |
s输出结果为:
➜ shell ./3_str.sh this is $name this is bob |
拼接
name="zhangzhen" #使用双引号拼接 a="hello,"$name"" b="hello,${name}" #使用单引号拼接 c='hello,'$name'' d='hello,${name}' echo $a $b $c $d |
输出结果:
hello,zhangzhen hello,zhangzhen hello,zhangzhen hello,${name}
|
长度
str="hi,jerk morning!!" echo ${#str} #输出17 expr length "$str" #输出17,因为str字符串中含有空格,因此需要添加双引号 |
截取
shell截取字符串通常有两种方式:从指定位置开始截取和从指定字符(子字符串)开始截取。
从指定位置开始截取:
str="ilovefish" echo ${str:1:4} #love echo ${str:4} #efish echo ${str:0-4:3} #fis echo ${str:0-4} #fish |
str:1:4
表示从第二个字符开始,截取四个字符,故输出love
!
str:4
表示从第四个字符开始到最后。
str:0-4:3
表示从倒数第4个开始,往后截取3个字符。
str:0-4
表示从倒数第4个开始到最后。
从指定字符开始截取:
var="http://www.baidu.com/1.html" echo ${var#*//} #www.baidu.com/1.html echo ${var##*/} #1.html echo ${var%/*} #http://www.baidu.com echo ${var%%/*} #http: |
#
号是运算符,*//
表示从左边开始删除第一个 //
号及左边的所有字符。
##*/
表示从左边开始删除最后(最右边)一个 /
号及左边的所有字符。
%/*
表示从右边开始,删除第一个/
号及右边的字符。
%%/*
表示从右边开始,删除最后(最左边)一个 /
号及右边的字符。
借助shell命令做字符串截取:
var="http://www.baidu.com/123.com" echo $var | cut -c1-4 #http echo $var | cut -c8- #www.baidu.com/123.com echo $var | cut -d ":" -f 1 #http |
查找
str="ilove china" echo `expr index "$str" io` |
查找字符 i 或 o 的位置(哪个字母先出现就计算哪个)
数组
bash支持一维数组(不支持多维数组),并且没有限定数组的大小。
定义
数组名=(值1 值2 ....) arr=(1 2 3 4) arr=( 1 2 3 4 ) arr[0]=1 arr[1]=2 ... |
读取
echo ${arr[0]}
|
长度
length=${#arr[@]} #获取元素个数 length=${#arr_name[*]} #获取元素个数 length=${#arr[n]} #获取单个元素的长度 |
arr=(1 2 3 "hello") echo ${arr[3]} #hello length1=${#arr[*]} length2=${#arr[@]} length3=${#arr[3]} echo ${length1} $length2 $length3 # 4 4 5 |
注释
#
单行注释。
EOF
多行注释。
:<<EOF 注释内容... ... EOF |
注意,注释符号EOF
可以使用其他符号,如'
或!
参数
传递参数
我们可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n,n 代表执行脚本的第n
个参数。
如下实例:
echo "Shell传参实例!" echo "执行的文件名:$0" echo "第一个参数:$1" echo "第二个参数:$2" |
执行结果如下:
➜ shell ./5_para.sh 1 2 Shell传参实例! 执行的文件名:./5_para.sh 第一个参数:1 第二个参 |
参数处理
以下,可以使用一些特殊字符来处理参数:
参数处理 | 说明 |
---|---|
$# | 传递到脚本的参数个数 |
$* | 以一个单字符串显示所有向脚本传递的参数。 如”$*”用「”」括起来的情况、以”$1 $2 … $n”的形式输出所有参数。 |
$$ | 脚本运行的当前进程ID号 |
$! | 后台运行的最后一个进程的ID号 |
$@ | 与$*相同,但是使用时加引号,并在引号中返回每个参数。 如”$@”用「”」括起来的情况、以”$1” “$2” … “$n” 的形式输出所有参数。 |
$- | 显示Shell使用的当前选项,与set命令功能相同。 |
$? | 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。 |
echo "Shell传参示例!" echo "第一个参数为:$1" echo "参数个数为:$#" echo "参数为:$*" |
执行结果为:
➜ shell ./5_para_1.sh 1 2 3 4 5 Shell传参示例! 第一个参数为:1 参数个数为:5 参数为:1 2 3 4 5 |
$* 与 $@ 区别:
- 相同点:都是引用所有参数。
- 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 “ * “ 等价于 “1 2 3”(传递了一个参数),而 “@” 等价于 “1” “2” “3”(传递了三个参数)。
echo "-- \$*演示 --" for i in "$*"; do echo $i done echo "-- \$@演示 --" for i in "$@"; do echo $i done |
执行结果如下:
➜ shell ./5_para_2.sh 1 2 3 -- $*演示 -- 1 2 3 -- $@演示 -- 1 2 3 |
中括号
Shell 里面的中括号(包括单中括号与双中括号)可用于一些条件的测试:
- 算术比较, 比如一个变量是否为0,
[ $var -eq 0 ]
。 - 文件属性测试,比如一个文件是否存在,
[ -e $var ]
, 是否是目录,[ -d $var ]
。 - 字符串比较, 比如两个字符串是否相同,
[[ $var1 = $var2 ]]
。
算术比较
对变量或值进行算术条件判断:
[ $var -eq 0 ] # 当 $var 等于 0 时,返回真 [ $var -ne 0 ] # 当 $var 不等于 0 时,返回真 |
需要注意的是 [ 与 ] 与操作数之间一定要有一个空格,否则会报错。比如下面这样就会报错:
[$var -eq 0 ] 或 [ $var -ne 0]
|
操作符 | 意义 |
---|---|
-gt | 大于 |
-lt | 小于 |
-ge | 大于或等于 |
-le | 小于或等于 |
可以通过 -a (and) 或 -o (or) 结合多个条件进行测试:
[ $var1 -ne 0 -a $var2 -gt 2 ] # 使用逻辑与 -a [ $var1 -ne 0 -o $var2 -gt 2 ] # 使用逻辑或 -o |
文件属性测试
使用不同的条件标志测试不同的文件系统属性。
操作符 | 意义 |
---|---|
[ -f $file_var ] |
变量 $file_var 是一个正常的文件路径或文件名 (file),则返回真 |
[ -x $var ] |
变量 $var 包含的文件可执行 (execute),则返回真 |
[ -d $var ] |
变量 $var 包含的文件是目录 (directory),则返回真 |
[ -e $var ] |
变量 $var 包含的文件存在 (exist),则返回真 |
[ -c $var ] |
变量 $var 包含的文件是一个字符设备文件的路径 (character),则返回真 |
[ -b $var ] |
变量 $var 包含的文件是一个块设备文件的路径 (block),则返回真 |
[ -w $var ] |
变量 $var 包含的文件可写(write),则返回真 |
[ -r $var ] |
变量 $var 包含的文件可读 (read),则返回真 |
[ -L $var ] |
变量 $var 包含是一个符号链接 (link),则返回真 |
使用方法如下:
fpath="/etc/passwd" if [ -e $fpath ]; then echo File exits; else echo Does not exit; fi |
字符串比较
在进行字符串比较时,最好使用双中括号 [[ ]]. 因为单中括号可能会导致一些错误,因此最好避开它们。
检查两个字符串是否相同:
[[ $str1 = $str2 ]]
|
当 str1等于str1等于str2 时,返回真。也就是说,str1 和 str2 包含的文本是一样的。其中的单等于号也可以写成双等于号,也就是说,上面的字符串比较等效于 [[ $str1 == $str2 ]]。
注意 = 前后有一个空格,如果忘记加空格, 就变成了赋值语句,而非比较关系了。
字符串的其他比较情况:
操作符 | 意义 |
---|---|
[[ $str1 != $str2 ]] |
如果 str1 与 str2 不相同,则返回真 |
[[ -z $str1 ]] |
如果 str1 是空字符串,则返回真 |
[[ -n $str1 ]] |
如果 str1 是非空字符串,则返回真 |
使用逻辑运算符 && 和 || 可以轻松地将多个条件组合起来, 比如:
str1="Not empty" str2="" if [[ -n $str1 ]] && [[ -z $str2 ]]; then echo str1 is nonempty and str2 is empty string. fi |
test 命令也可以从来执行条件检测,用 test 可以避免使用过多的括号,[] 中的测试条件同样可以通过 test 来完成。
if [ $var -eq 0 ]; then echo "True"; fi
|
等价于:
if test $var -eq 0; then echo "True"; fi
|
原创文章,作者:小嵘源码,如若转载,请注明出处:https://www.lcpttec.com/shelljb/