学习shell
第一个shell文件:打印hello world!~
其实在vi+文件名之前可以有另一个命令:touch+文件名
因为vi+文件名表示打开该文件(如果没有就自动创建一个文件)
而touch+文件名才表示创建一个新的文件
vi/vim hello //创建一个叫hello的文件
#! /bin/bash //无实际意义,告诉我们这是用bash终端
echo "hello world~"/hello world!~ //两种方式都可以,可以不加单双引号,echo就是输出的意思
sudo chmod +x hello
./hello
第二个shell文件,添加其他命令
vi/vim hello
echo "hello world"
echo -------------
cd / //切换到根目录
ls //根目录下有那些文件
echo -----------------
date //打印日期
./hello //运行文件
基础知识
1.自定义变量
1.1 变量名=值
haha=1
echo $haha
1.2 把一个变量赋值给另一个变量
a='hello' //注意等号两边不能有空格
b=$a
echo $b
name=jack //这里可以不加单引号
message=他的名字叫${name}! //如果最后没有内容(这里是!),可以不用大括号{}
echo $message
1.3 定义只读变量
haha=1
echo $haha
readonly haha
1.4 删除变量:只能删除普通变量,不能删除只读变量
hehe=2
echo $hehe
unset hehe //删除变量hehe
echo $hehe
2.环境变量:例如($PATH),可视作全局变量
2.1 临时添加环境变量:只在当前终端有效,该终端关闭之后,变量就失效
export lala=1 //重启一个终端就无效啦
echo $lala
export a=1
echo $a
b=2
echo $b
bash //在该终端下开启子终端,终端里的终端
echo $b //不会再显示了,普通变量不能在子终端中使用
echo $a
exit //退出子终端
echo $b
unset a //删除环境变量
echo $a
2.2 永久添加环境变量
2.2.1 方案一:添加完仅对当前用户有效,切换到其他用户,其他用户不能使用这个环境变量
通过修改~/.bashrc文件,在最后一行上添加上export 变量名=变量值,然后保存退出
两种生效方法:
1.关闭当前终端,重新打开一个新终端窗口就能生效
2.输入"source~./bashrc"命令,立即生效
有效期限:永久生效
用户局限:仅对当前用户
vi .bashrc //在主目录中打开
export haha=123456789 //找到最后一行,然后点击i开始插入所示代码,然后ESC,然后输入:wq保存退出
source ./bashrc //让文件生效生效
echo $haha
2.2.2 方案二
通过修改/etc/profile文件
sudo vi /etc/profile
export haha=1
生效方法:系统重启
有效期限:永久有效
用户局限:对所有用户
sudo vi /etc/propile
export haha=1213131 //在文档最后一行输入,i表示插入,然后保存退出(同上)
echo $haha //重启之后就可以使用在所有终端了
3.内部变量/位置参数/命令行参数:linux提供的特殊类型变量,例如内部变量$$储存李当前进程进程号
3.1 $0:编译脚本的命令行
3.2 $n:传递给脚本或函数的参数,n是数字,$1表示第一个参数,以此类推
当参数超过10个,用{}表示,例如${12}
3.3 $#:传递给脚本或函数的参数个数
3.4 $*:传递给脚本或函数的所有参数(所有参数可看作一个整体的字符串)
3.5 $@:传递给脚本或函数的所有参数(每个参数都是单独的字符)
3.6 $?:函数的返回值,或成为上个命令的退出状态(大部分命令执行成功时退出状态为0,失败为1)
3.7 $$:当前shell进程号
vi haha
#! /bin/bash
echo 文件名:$0 //可加引号,可不加
echo 第一个参数:$1
echo 第二个参数:$2
echo 所有参数:$*
echo 所有参数:$@
echo 参数个数:$#
echo 当前进程ID:$$
bash haha 11 22 33 //haha是指文件名,后面三个是赋的值
vi haha
#! /bin/bash
set 11 22 33
echo 文件名:$0 //可加引号,可不加
echo 第一个参数:$1
echo 第二个参数:$2
echo 所有参数:$*
echo 所有参数:$@
echo 参数个数:$#
echo 当前进程ID:$$
4 变量值输出
4.1 命令echo
str="您好~"
echo $str
与字符混用
str="您好!"
echo "$str,这是一个测试"
用{}与字符混用
month=9
echo "2021-${month}-10"
str="您好"
echo "$str",$"
4.2 命令printf
与echo类似
printf"您好!n"
可以带参数,和C语言,python用法相同,%s表示字符串,%d表示整数
printf "我是一名%s,今年%d岁n" "学生" "30"
4.3 从用户输入获取变量值
使用read命令,类似与python中input
创建一个文件,展示read写法
vi test
#! /bin/bash
read -p "请输入两个数字" d1 d2
echo "输入的第一个数字是$d1"
echo "输入的第二个数字是$d2"
bash test
4.3 变量替换
4.3.1 ${haha}:正常使用变量haha
4.3.2 ${haha:-$hehe}:如果变量haha为空,返回变量hehe的值,不改变haha的 值
4.3.3 ${haha:=$hehe}:如果变量haha为空,返回变量hehe的值,将hehe的值赋值给haha
4.3.4 ${haha:?$hehe}:如果变量haha为空,将hehe发送到标准错误输出(终端)
用来检测haha是否被赋值,未被正常赋值,脚本运行将暂停报错
4.3.5 ${haha:+$hehe}:如果变量haha被定义,返回变量hehe的值,不改变haha的值
5. 数组
bash仅支持一维数组,下标也是从0开始,数组元素用空格分开
定义数组:数组名=(值1 值2 ....值n)
shuzu=(A B C D)
echo ${shuzu[0]} //取数组中的第一个值
echo ${shuzu[*]} //取数组中的所有值
echo ${shuzu[@]} //取数组中的所有值
echo ${#shuzu[@]} //数组的元素个数
echo ${#shuzu[1]} //数组中第二个元素的长度
6 数学运算
6.1 整数加减乘除
6.1.1 直接计算
echo $[1+1]
echo $[9-1]
echo $[9*3]
echo $[9/8] //这个答案为1
6.1.2 计算并给变量赋值
a=$[1+1]
b=$[3-2]
c=$[7*1]
d=$[8/7]
echo $a $b $c $d
6.1.3 变量间的计算赋值
直接相加获得字符串
a=1
b=2
c=$a+$b
echo $c
使用let命令,获得数字结果
a=1
b=1
let.c=$a+$b
echo $c
使用双括号(())获得数字结果
a=1
b=2
((c=a+b))
echo $c
6.2 浮点数(小数)加减乘除
6.2.1 加减
echo 1.1+2.2|bc
echo 2.1-2|bc //小于1的小数之前的0被省略
printf %.2f `echo 2-1.3|bc //保留两位小数,注意的是,这个不单引号,而是ESC下面那个键`
6.2.2 乘
其中scale是控制保留小数点位数的
echo "1.1*1.1"|bc
echo "scale=2;1.1*1.1"|bc //小数点保留的位数为2
6.2.3 除
其中scale是控制保留小数点位数的
echo "4/3"|bc
echo "scale=3;4/3"|bc
6.3 计算并给变量赋值
c=$(echo "1.1*1.1"|bc)
echo $c
c=$(echo "scale=2;1.1*1.1"|bc)
echo $c
6.4 变量间计算赋值
a=1.1
b=1.2
x=$(echo "scale=3;$a*$b"|bc)
echo $x
7 流程控制语句
7.1 条件语句
7.1.1 if判断
if...fi结构
如果判断条件为真,就执行then后面的语句
if [判断条件] //if和判断条件之间有一个空格,判断语句和[]之间也有空格
then
程序语句
fi
vi test
a=3
b=3
echo a等于$a
echo b等于$
if [ $a == $b ]
then
echo a等于b
fi
判断条件介绍
用[ 判断条件 ]或者 test 判断条件,test 不常用
例:[ $a ==b
]
中
b ]中
b]中a和$b的两侧必须有空格
相等:-eq 例:[ $a -eq $b ] 或 [ $a == $b ]
不等于:-ne 例:[ $a -ne $b ] 或 [ $a != $b ]
大于:-gt 例:[ $a -gt $b ]
小于:-lt 例:[ $a -lt $b ]
小于等于:-ge 例:[ $a -ge $b ]
大于等于:-le 例:[ $a -le $b ]
相等:= 例:[ $a = $b ]
不想等:!= 例:[ $a != $b ]
检测字符串长度是否为0:-z 例:[ -z $a ]
检测字符串长度是否不为0:-n 例:[ -n $a ]
检测字符串长度是否为空:直接放入字符串变量 例:[ $a ]
-d 检测文件是否是目录 例:f="/home/q.text" [ -d $f ]
-f 检测文件是否是普通文件 例:[ -f $f ]
-r 检测文件是否可读 例:[ -r $f ]
-w 检测文件是否可写 例:[ -w $f ]
-x 检测文件是否可执行 例:[ -x $f ]
-s 检测文件大小是否大于0 例:[ -s $f ]
-e 检测文件是否存在 例:[ -e $f ]
布尔运算符
与:-a 例:[ $a==$b -a $c==$d ]
或:-o 例:[ $a == $b -o $c ==$d ]
非:! 例:a=false 或 a=true [!$a ]
if...else...if结构
如果判断条件为真,就执行语句1
否则,执行语句2
if [ 判断条件 ]
then
程序语句1
else
程序语句2
fi
vi tst
a=$1 //在这里其实有一个$0,但是$0输出得到的是该文件的名字,在这里无意义
b=$2
echo a等于$1
echo b等与$2
if [ $1 == $2 ]
then
echo a等于b
else
echo a不等于b
fi
if...elif...if结构
如果判断条件1为真,就执行语句1,然后结束
如果判断条件1为假,进行判断条件2的判断,为真就执行语句2
否则,执行语句3
if [ 判断条件1 ]
then
程序语句1
elif [ 判断条件2 ]
then
程序语句2
else
程序语句3
fi
a=$1
b=$2
echo a等于$1
echo b等于$2
if [ $a==$b ]
then
echo a等于b
elif [ $a -gt $b]
then
echo a小于b
else
echo a大于b
fi
if结构可以嵌套,一个If结构可以包含另一个if结构
if结构中的elif和else都是可选的,不必需有
7.1.2 case判断
case是一种多选择结构,可以匹配值,如果匹配成功,执行对应的语句,执行后结束,不执行其他语句
case 值 in
值1)
语句1
;;
值2)
语句2
;;
值3)
语句3
;;
×)
其他语句
esac
echo 1:榴莲
echo 2:椰子
echo 3:水蜜桃
echo 4:哈密瓜
echo 5:芒果
read -p “请选择你喜欢的水果:fruit //这里需要在变量之前有一个空格,或者直接把变量之前的字符用双引号
case $fruit in
1)
echo 你喜欢榴莲
;;
2)
echo 你喜欢椰子
;;
3)
echo 你喜欢水蜜桃
;;
4)
echo 你喜欢哈密瓜
;;
5)
echo 你喜欢芒果
;;
*)
echo 你可能不喜欢水果
esac
7.2 循环结构
7.2.1 while循环
while 判断条件
do
语句
done
当判断条件为真时,循环执行语句,直到判断条件为假时,跳出循环
a=0
read -p 请输入一个数字: num
while [ $a -lt $num ]
do
echo $a
((a=a+1))
done
cat tes //可以看见文件中的代码
7.2.2 until循环
do
语句
done
until 执行循环语句,直到until判断条件为真时结束
a=0
read -p 请输入一个数字: num
until [ $a == $num ]
do
echo $a
((a=a+1))
done
5.2.3 for循环
for 变量 in 变量
do
语句
done
循环次数等于列表中元素个数,每次循环,变量值等于当前列表中对应的元素
for x in 1 2 3 4 5 6 7 8 9
do
echo $x
done
7.2.4 跳出循环
break
break 用来终止一个循环
break n ,其中n表示跳出循环的几层循环,默认是1
for x in 1 2 3 4 5 6
do
echo $x
if [ $x == 2 ]
then
break
fi
done
for x in 1 2 3
do
for y in 3 4 5
do
if [ $x == $y ]
then
echo x=$x,y=$y,x=y,跳出循环
break 2
else
echo x=$x,y=$y,x!=y,循环继续
fi
done
done
continue
continue 用来跳过本次循环,直接进行下一次循环
continue n ,其中n表示跳出的几层循环,默认是1
for x in 1 2 3 4 5
do
if [ $x == 3 ]
then
continue
fi
echo x=$x
done
exit
exit n, 退出当前终端,并设置退出值为n,不设置n默认为0
可使用$?查看最后一个命令的退出值
echo hello
exit 123
echo hello
echo $?
7.3 多命令组合执行
7.3.1 &&
cd / && l
// 首先进入根目录,然后查询有什么文件
rm qqq && l //rm+文件名表示删除该文件
// 删除一个不存在的文件然后查询当前文件夹下有什么文件
7.3.2 ||
cd / || l
//命令1进入根目录,命令2查询当前目录有什么文件
cd haha || mkdir haha
//进入一个名叫haha的文件夹,当文件夹不存在(即命令1执行失败),创建一个名叫haha的文件夹
7.3.3 &&和|| 联合使用
用法:命令1 && 命令2 || 命令3
含义:从左往右看先看命令1和命令2,执行结果作为一个整体,可以这么理解(命令1 && 命令2)|| 命令3,括号里面两个命令都执行成功视为成功,则不执行命令3,有一个失败就视为失败,执行命令3
cd / && l || echo "命令1或命令2执行失败"
用法:命令1 || 命令2 && 命令3
含义:从左往右看先看命令1和命令2,执行结果作为一个整体,可以这么理解(命令1 || 命令2)&& 命令3,括号里面两个命令有一个执行成功视为成功,则不执行命令3,都失败就视为失败,执行命令3
cd / || l && echo "命令1或命令2执行成功"
7.3.4 使用括号()的组合命令
命令1 || (命令2 && 命令3)
命令1失败,执行(命令2 && 命令3),(命令2 && 命令3)看成整体
echo 1 || (echo 2 && echo 3)
8 函数
8.1 函数定义
函数名()
{
函数内容
return 返回值
}
函数的返回值只能是整数,如果不加return返回值,将会把最后一条命令的退出值作为返回值
8.2 函数调用
函数名 参数1 参数2 …
8.3 实例
8.3.1 调用函数,打印hello world
touch hello
vi hello
hello()
{
echo "hello world!~"
}
hello //要想函数被调用,这里要写上文件名
bash hello或者./hello
8.3.2 在函数外部如何使用函数中的变量
shell 中的函数被调用后,函数外部可直接使用内部定义的变量
hello()
{
haha="hello world!"
}
hello
echo $haha
8.3.3 获取函数的输出值赋值给变量
hello()
{
echo "hello world!"
}
haha=$(hello)
echo $haha
8.3.4 带返回值的函数
参数传递使用 $1 $2等表示,返回值用$?表示
love()
{
((haha=$1+$2+$3))
echo 第一个参数为 $1
echo 第二个参数为 $2
echo 第三个参数为 $3
return $haha
}
love 3 6 4
echo love函数的返回值为$?
一些内置命令
read是shell内置命令,用于从标准输入中读取数据并赋值给变量,如果没有进行重定向,默认就是从终端控制台读取用户输入的数据,如果进行了重定向,那么可以从文件中读取数据.
语法:read [options] [var1 var2]
options表示选项,如下所示,var表示用来存储数据的变量,可以是一个,也可以是多个
-n num 读取num个字符,而不是整行字符
-p prompt 显示提示信息,提示内容为prompt
-s 静默模式,不会再屏幕上显示输入的字符
-t seconds 设置超时时间,单位为秒,如果用户没有在指定时间内输入完成,那么read将会返回一个非0的退出状态,表示读取失败.
cat 文件名 //显示代码内容
#! /bin/bash //说明该脚本是用哪一种shell编写的,通常放在脚本的第一行,从而调用相应的解释程序予以执行
#ShowHello
#To show hello to somebody
echo -n "Enter Your Name" //参数-n的作用是不换行,echo默认换行
read name //从键盘输入信息
echo "Hell0 $name"
Linux 系统中最常见的shell类型为Bourne shell(简称sh),C shell(简称csh),Korn shell(ksh),Bourne-again shell(简称bash)
1.命令记忆功能 ./bash_history
2.自动补全功能 Tab键是个好东西
3.别名设置功能 alias ll='ls -l' 左边是新的名字,右边是之前的名字或者属性
通配符
*
*可以任意字符的0次或者多次出现
例如:
用户输入 ls -l file* ,在这个命令中,使用了通配符,shell在执行命令之前,会以合适的文件名进行替换,找出当前目录中以file开头的文件名并执行。所以,当shell使用通配符时,在参数传递给程序之前,通配符已经变成实际文件名并执行。所以,当shell使用通配符时,在参数传递给程序之前,通配符已经变成实际文件名,如果通配符不能匹配任何文件,shell将会显示一个报错信息。
* 可以匹配/(斜线)字符之外的任何字符,因为/用作路径名中的定界符
?
? 匹配任意单个字符(除/之外)
d? 表示以‘d’开头的两个字符的文件名
?? 表示任意两个字符的文件名
?*y 表示至少两个字符,并且以“y”结束的文件名
[] 一对方括号
[] 将一组字符列表括起来,其作用是匹配该字符组所限定的任何一个字符,即指定列表中的任意一个字符。
例如:space.[co]匹配space.o或者space.c
[Hh]* 匹配以H或者h开头的文件名
[] 中无论有几个字符,都只代表一个字符,在[]中,也可以用-指定字符的范围,例如[1-9]
{} 大括号
{string1,string2 ,sring3...}匹配string1或者其他的字符串
但这种写法只在bash,tcsh和C sh
输出的时候有一个顺序执行,需要在各个命令之间加上;
例如:
ls;date;pwd;cd /user
输入输出重定向符
标准输入重定向:
command <fle //将文件作为命令输入
//例如:bash < sho1的意思是让bash执行时,直接从sh01中读取数据,而不必交互式地从键盘上输入
//wc -l <file 表示统计file文件中有多少行文本
command <<分界符 //从标准输入中读入,直到遇见分界符才停止
//
标准错误输出重定向:
command 2>file //以覆盖的形式,把command中的错误信息输出到file文件中
command 2>>file //以追加的形式,把command的错误信息输出到file文件中
标准输出重定向:
command >file //以覆盖的形式,把command中的正确结果输出到file文件中
command >>file //以追加的形式,把command的正确信息输出到file文件中
管道符
在shell中,管道实际上就是进程之间的一个通信工具,那么用在Linux命令中主要是方便两条命令互相之间可以相互通信。
管道符是"|",主要是把两个应用程序连接在一起,然后把第一个应用程序的输出,作为第二个应用程序的输入。如果还有第三个应用程序的话,可以把第二个程序的输出,作为第三个应用程序的输入,以此类推。
如 [ ls | grep test.s ],在当前文件过滤出test.sh文件:
[root@lincoding /]# ls
bin data etc lib lost+found net opt root selinux sys usr
boot dev home lib64 media mnt proc sbin srv test.sh tmp
[root@lincoding /]# ls | grep test.sh
test.sh
管道符"|"就把ls命令的文件列表输出给到了[grep test.sh]命令来过滤文件。
管道符还有一个需要注意的地方,我们可以通过下面的命令观察到,在使用管道符的时候,管道符会为两条命令产生了子进程
[root@lincoding /]# cat | ps -f
UID PID PPID C STIME TTY TIME CMD
root 2627 2623 0 14:57 pts/0 00:00:00 -bash
root 88029 2627 0 19:51 pts/0 00:00:00 cat
root 88030 2627 0 19:51 pts/0 00:00:00 ps -f
父进程bash的pid为2627,子进程cat的pid为88029,子进程ps -f的pid为88030。
由于管道符是会为连接的命令产生子进程,所以也是不会影响当前环境的。
我们用cd /home/ | ls命令验证下,运行结果如下:
[root@lincoding /]# cd /home/ | ls
bin data etc lib lost+found net opt root selinux sys usr
boot dev home lib64 media mnt proc sbin srv test.sh tmp
[root@lincoding /]# pwd
/
从以上的运行结果可以得知,类似切换目录cd这种会影响当前环境的命令,在使用了管道符之后,就没有对当前环境造成影响了。
如果使用分号";"连接两条命令会如何呢?
[root@lincoding /]# cd /sys/ ; ls
block bus class dev devices firmware fs hypervisor kernel module power
[root@lincoding sys]# pwd
/sys
可以得知,通过分号";"连接,cd命令会对当前环境造成影响。
原文地址:https://blog.csdn.net/weixin_62529383/article/details/126844238
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_44930.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!