简介
Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。
Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
<img />技术小贴
业界所说的 shell 通常都是指 shell 脚本,Shell 脚本(shell script),是一种为 shell 编写的脚本程序。
shell种类很多,包括sh、bash、xsh、ksh,其中bash是大多数Linux系统默认的shell,下面也将以bash为例。
简单的shell脚本如下:
#!/bin/bash
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 命令可以将变量定义为只读变量,只读变量的值不能被改变。
#!/bin/bash
var=123
echo ${var}
readonly var
var=456
echo ${var}
删除
使用 unset 命令可以删除变量。
变量被删除后不能再次使用。unset 命令不能删除只读变量。
类型
shell存在三种变量类型:
局部变量:局部变量在脚本或命令中定义,仅在当前shell实例中有效。
环境变量:所有的程序,包括shell启动的程序,都能访问环境变量。
shell变量:由shell程序设置的特殊变量,包括局部变量和全局变量。
字符串
定义
字符串可以用单引号,也可以用双引号,也可以不用引号。
单引号里的任何字符都回原样输出;单引号字符串中的单引号必须成对出现。
双引号里可以出现变量和转义字符。
#!/bin/bash
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截取字符串通常有两种方式:从指定位置开始截取和从指定字符(子字符串)开始截取。
从指定位置开始截取:
#!/bin/bash
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]} #获取单个元素的长度
#!/bin/bash
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个参数。
如下实例:
#!/bin/bash
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表示没有错误,其他任何值表明有错误。
#!/bin/bash
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”(传递了三个参数)。
#!/bin/bash
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/