shell
查看本地支持的shell
cat/etc/shells
/bin/sh
/bin/bash
/usr/bin/bash
/bin/rbash
/usr/bin/rbash
/bin/dash
/usr/bin/dash
查看本地默认shell
ls -l /bin/ |grep bash
-rwxr-xr-x 1 root root 1183448 4月 18 17:14 bash
-rwxr-xr-x 1 root root 6794 4月 18 17:14 bashbug
-rwxr-xr-x 1 root root 2446 1月 26 2020 dh_bash-completion
lrwxrwxrwx 1 root root 4 4月 18 17:14 rbash -> bash
rbash 是乌班图默认的
格式开头
#!/bin/bash
第一个脚本
#!/bin/bash
echo "hello word"
脚本常见的执行方式
1.直接使用bash执行
bash hello.sh
2.全路径bash
bash /home/player3/shells/hello.sh
sh /home/player3/shells/hello.sh
3.相对路径
./hello.sh
bash: ./hello.sh: 权限不够
需要给脚本增加权限
chmod +x hello.sh
4.使用点命令
. hello.sh
5.使用source命令
source hello.sh
前面3种都是使用了子bash进程来执行,后两种是逐行执行当前的脚本
变量
系统预定义变量
$HOME ,$PWD,$SHELL,$USER等等
显示当前shell中所有变量:set
set
会显示所有变量 x=xxx的形式
全局的环境变量
子shell也有效
echo $HOME
查看环境变量的值
查看所有的全局环境变量
env
printenv
局部的环境变量
只在当前shell有效
自定义变量
1.变量名可以由字母,数字,下划线组成,但是不能以数字开头,环境变量名建议大写
2.等号两侧不能有空格
3.在bash中,变量默认类型都是字符串类型,无法直接进行数值运算
4.变量的值如果有空格,需要使用双引号,或单引号括起来
定义局部变量
命令行输入 my_var=‘hello word’
echo $my_var
但是这是全局的还是局部的呢
看全局的: env |grep my_var 看所有的环境变量:set |grep my_var 在所有的环境变量中查到了这个值,所以这个环境变量是局部的
导出到全局变量
export my_var
子shell修改不会改变现有全局变量的数据
变量的数据类型
变量的数据类型初始并没有定义或者默认字符串
数值运算
a=$((1+5))
a=$[5+9]
命令行的操作:expr 1 + 2
乘法的时候需要注意:expr 1 \* 2
为了更加简便 $((运算式))或$[运算式]
计算两个数的和
sum=$[$1+$2] echo sum=$sum
只读变量
readonly b=5
b=10
bash:b:只读变量
撤销变量
unset a
特殊变量
$n
n为0-9,0为脚本的名称,1-9代表第一到第九的参数,9以上需要${10}
sh文件中单引号会把¥原封不动的显示出来
test测试:
hello.sh文件
#!/bin/bash
echo '-------$n---------'
echo name:$0
echo get:$1
echo get $2
执行后:./hello.sh liming wangwu
./hello.sh liming wangwu
-------$n---------
name:./hello.sh
get:liming
get wangwu
如何把脚本名称显示正常?
echo name:$(basename $0)
获取所有输入参数个数
功能描述,获取所有输入参数个数,用于循环,判断个数是否正确以及加强脚本健壮性
$#
所有参数,每个参数区分对待
命令:
liming wangwu
最后一次执行的命令的返回状态
#? 在最后一次执行的命令的返回状态,这个变量的值如果为0,证明上一个命令正确,如果这个变量的值非0(具体哪个数,由命令来决定),则证明上一个命令执行不正确了
sh文件直接执行的方案
直接放在bin目录和sbin目录
最好不要直接复制到这些目录
PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
可以丢到这些目录下或者配置环境变量
条件判断
test 条件非空为true,正确为true,否则为false
常用
-eq 等于 -ne 不等于
-lt 小于 -le小于等于
-gt 大于 -ge大于等于
如果是字符串比较==判断相等,!=判断不等于
按照文件权限进行判断
-r 有读的权限
-w 有写的权限
-x 有执行的权限
按照文件类型进行判断:
-e 文件存在
-f 文件存在并是一个常规的文件
-d 文件存在并且是一个目录
test 1=1
#?
1.
案例
1.23是否大于等于22
[23 -ge 22]
echo $?
2.helloword.sh是否有读写权限
[- w helloworld.sh]
echo $?
3./home/at.txt目录文件是否存在
[-e /home/at.txt]
echo $?
if判断
单分支:
if[条件判断式];then
程序
fi
------------------------------
或者
if[条件判断式];
then
程序
fi
--------------------------
多分支
if[条件判断式];
then
程序
elif [条件判断式];
then
程序
else
程序
fi
1.[条件判断式] 中括号和条件表达式之间必须有空格
2.if后有空格
case判断
case $变量名 in
“值1”)
结果
;;
“值2”)
结果
;;
*)
esac
注意事项:
1.case 行尾必须单词 in ,每个模式匹配必须右括号)结束
2.双分号;;表示命令序列结束,相当于java的break
最后的*)表示默认模式,相当于default
案例
case $1 in
1)
echo 'one'
;;
2)
echo 'two'
;;
*)
echo "default"
esac
for循环
基本语法
双小括号可以跟数学运算表达式
for((初始值;循环控制条件;变量变化)) do 程序 done
实操1+到100
sum=0 for((i=0;i<=100;i++)) do sum=$[$sum+i] done echo $sum
循环中的$@和$*有什么区别, 如果没被引号引起来的化都是一行一行的打印输出的, $*会把数据显示为一行输出
while
a=1
while [ $a -le $1]
do
sum=$[$sum+$a]
a=$[$a+1]
done
echo $sum
控制台输入
read 选项 参数
选项 -p: 指定读取值时的提示符
-t: 指定读取时的等待的时间,如果-t不加默认一直等待
参数:变量:指定读取值的变量名
提示7秒内,读取控制台输入的名字
read -t 7 -p "name in 7": NN
echo $NN
系统函数
basename
basename 会删除掉所有的前缀包括最后一个(/)字符然后将字符串形式显示出来
basename可以理解为路径里的文件名称
选项:suffx为后缀,如果suffix被指定了,basename会将pathname或string中的suffix去掉
dirname
dirname文件绝对路径,从给定的包含绝对路径的文件名中去除文件名,然后返回剩下的路径
可以理解为取文件路径的绝对路径
date 显示当前日期
date
2022年 06月 23日 星期四 15:06:40 CST
date +%s
1655968039
案例:根据控制台输入生成文件附带随机字符
#!/bin/bash filename="$1"_log_$(date +%s) echo $filename ~
./hello.sh player3
player3_log_1655968339
调用系统函数
$(函数名 )
自定义函数
function name() {
statements
[return value]
}
对各个部分的说明:
function是 Shell 中的关键字,专门用来定义函数;
name是函数名;
statements是函数要执行的代码,也就是一组语句;
return value表示函数的返回值,其中 return 是 Shell 关键字,专门用在函数中返回一个值;这一部分可以写也可以不写。
由{ }包围的部分称为函数体,调用一个函数,实际上就是执行函数体中的代码。
函数定义的简化写法
如果你嫌麻烦,函数定义时也可以不写 function 关键字:
name() {
statements
[return value]
}
如果写了 function 关键字,也可以省略函数名后面的小括号:
function name {
statements
[return value]
}
我建议使用标准的写法,这样能够做到“见名知意”,一看就懂。
Shell 也不限制定义和调用的顺序,你可以将定义放在调用的前面,也可以反过来,将定义放在调用的后面。
经验:
1.必须在调用函数地方之前,先声明函数,shell脚本是逐行执行的,不会像其他语言一样先编译
2.函数返回值,只能通过$?系统变量获得,可以显示加return 返回,如果不加,将以最后一条命令运行结果,将返回值,return后跟数值
(0-255)
#!/bin/bash
function getsum(){
local sum=0
for n in $@
do
((sum+=n))
done
return $sum
}
getsum 10 20 55 15 #调用函数并传递参数
echo $?