赞
踩
shell就是一块包裹着系统核心的壳,处于操作系统的最外层,与用户直接对话,把用户的输入,解释给操作系统,然后处理操作系统的输出结果,输出到屏幕给与用户看到 结果。(例如用户输入ls命令,shell解释给操作系统是要查看目录,然后操作系统在编译给机器硬件,机器硬件返回给操作系统,操作系统在返回给shell,shell在解释给用户)
从我们登录linux,输入账号密码进入到linux交互式界面(交互式就是输入一条命令返回一条结果),所有的操作都是交给shell解释执行的。
我们想要获取计算机的数据,不可能每次都编写程序,编译后,在运行,在得到我们想要的,例如:你想找到一个文件,可以先写一段C语言的代码,然后调用系统函数,通过gcc编译后,运行程序才能找到文件。
因此有大牛开发出了shell解释器,让我们方便的使用Linux,例如:只要敲下ls -lh 这样的字符串,shell解释器就会针对这句话翻译,解释成ls -l -h 在执行,通过终端输出结果,无论是图形化或是命令行界面
即使我们使用的图形化,区别也只是:
命令行操作:shell解释执行后,输出结果到黑屏命令行界面
图形化操作,shell接受点击动作,输出图案数据
当命令或者程序语句写在文件中,我们执行文件,读取其中的代码,这个程序文件就称为shelll脚本。
在shell脚本里定义多条linux命令以及循环控制i语句,然后将这些linux命令一次性执行完毕,执行脚本文件的方式称之为,非交互式方式。
- windows中存在*.bat 批处理脚本
- linux中常用*.sh 脚本文件
在linux系统周昂,shell脚本或者称之为(bash shell程序),都是vim编辑,有linux命令,bash shell指令,逻辑控制语句和注释信息组成。
计算机程序中,shebang指的是出现在文本文件中的第一行前两个字符#!
在unix系统中,程序会分析shebang后面的内容,作为解释器的指令,例如
实例:
执行python脚本
#!/usr/bin/python
#coding:utf-8 解决python版本编码的问题
print("this")
执行:.hello.py
或者指定解释器去运行:/usr/bin/python ./hello.py
shebang
,重点推荐的方式绝对/相对
路径执行脚本,需要文件含有x权限执行的含义
,source等于点shell脚本语言很适合处理纯文本类型数据,且linux的哲学思想就是一切皆文件,如日志,配置文件,文本,网页文件,大多数哦都是纯文本类型的,因此shell可以方便的进行文本处理,好比强大的linux三剑客(grep awk sed)
shell语言定义的变量,数据类型默认都是字符串类型;例如int 数字数据类型
弱类型语言,在定义数据类型的时候,不用主动声明改类型
shell. name=28
强类型编程语言,就需要指定变量的数据类型,必需得对应上否则报错,比如golang
name 名字变量 ,字符串类型数据,string
age 年龄,数据存储最好,int
shell脚本语言属于一种弱类型语言 无需声明变量类型,直接定义使用。
强类型语言,必须先定义变量类型。确定是数字,字符串等,之后在赋予同类型的值。
[root@shiqi ~]# cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
默认的sh解释器
[root@shiqi ~]# ll /usr/bin/sh
lrwxrwxrwx. 1 root root 4 9月 18 09:20 /usr/bin/sh -> bash
其他脚本语言
bash有诸多方便的功能,有助于运维人员提升工作效率
bash笔记
shell会保留其会话中用户提交执行的命令
history #命令,查看历史命令记录,(包含文件中和内存中的历史记录) echo $HISTSIZE ##shell进程可保留的命令历史的条数 [root@shiqi ~]# echo $HISTSIZE 1000 echo $HISTFILE #存放历史命令的文件,用户退出登录后,持久化命令个数 [root@shiqi ~]# echo $HISTFILE /root/.bash_history ls -a ~/ .bash_history 存放历史命令的文件 [root@shiqi ~]# ls -a ~/.bash_history /root/.bash_history 参数: -c 清空内存中命令历史 -r 从文件中恢复历史命令 数字:显示最近n条命令 :history 10 !! 两个感叹号执行上次命令即左右寻找 [root@shiqi ~]# name=shiqi [root@shiqi ~]# echo $name shiqi
变量是暂时i存储数据的地方,是一种数据标记(房间号,标记了客人所在的位置),数据存储在内容空间,通过调用正确的变量名字,即可取出对应的值
变量定义与赋值,注意变量与值之间不得有空格
name="三三"
echo $name
echo ${name} 花括号是可以省略的
变量名
变量类型,bash默认吧所有变量都认为是字符串
bash变量是弱类型,无需事先声明类型,是将声明和赋值同时进行
变量名规则
名称定义要做到见名知意,切按照规则来,切不得引用保留关键字(help检查保留字)
只能包含数字,字母,下划线
不能以数字开头
不能用标点符号
变量名严格区分大小写
变量的作用域
pstree检查进程树
[root@shiqi ~]# var=su9
[root@shiqi ~]# bash 切换到子shell,
[root@shiqi ~]# echo $var
变量丢失
[root@shiqi ~]# exit
exit 退出子shell回到父shell,变量回来
[root@shiqi ~]# echo $var
su9
环境变量,也成为全局变量,针对当前shell以及其任意子进程,环境变量也分为,自定义、内置
两种环境变量
局部变量,针对在shell函数或是shell脚本中定义
位置参数变量,用于shell脚本中传递参数
特殊变量:shell内置的特殊功能 可以查看上一次变量有没有执行成功
shell的特殊变量,用在脚本,函数传递参数使用,有如下特殊的,位置参数变量
$0 获取shell脚本文件名,以及脚本路径
$n 获取shell脚本的第n个参数,n在1~9之间,如$1,$2,$9,大 于9则需要写,${10},参数空格隔开
$# 获取执行的shell脚本后面的参数总个数
$* 获取shell脚本所有参数,不加引号等同于¥@作用,加上引号”
$@ 不加引号效果同上$*,加引号,是接受所有参数为独立字符串,如"$1"."$2"
参数传递 ls -l 参数 例如: 参数的理解 bash test1.sh 参数1 参数2 参数3 位置参数的获取 ls -l $0 获取文件名 $1 获取第一个参数 ###########代码 #! /bin/bash echo '特殊变量 $0,$1,$2 ..的实践' echo '结果:' $0 $1 $2 echo ############################## echo '特殊变量参数$# 获取参数总个数' echo '结果:' $# echo ############################## echo '特殊变量参数$*实践' echo '结果:' $* echo ############################## echo '特殊变量参数$@实践' echo '结果:' $@ 执行结果 [root@shiqi ~]# bash name.sh shishi 180 180 180 180 特殊变量 $0,$1,$2 ..的实践 结果: name.sh shishi 180 特殊变量参数$# 获取参数总个数 结果: 4 特殊变量参数$*实践 结果: shishi 180 180 180 180 特殊变量参数$@实践 结果: shishi 180 180 180 180 注:set paste 是vim的粘贴模式
$@和$* 的区别 $@和$* 都表示传递给函数或脚本的所有参数 当$@和$* 不被双引号"" 包围时,他们之间没有任何区别,都是将接收到的每个参数看作一份数据,彼此之间以空格来分隔 但是当他们用双引号包围的时候,他们之间就会有区别了; 例如: "$*" 会将所有的参数从整体上看做一份数据,而不是把每一个参数都看成一份数据 "yu 180 180 180" "$@"仍然将每一个参数都看成一份数据,彼此之间是独立的 "yu" "180" "180" 比如传递了五个参数。那么对于"$*"来说,这5个参数会合并到一起形成一份数据,他们之间是无法分割的; 而对于"$@"来说,这5个参数是互相独立的,他们是5份数据 如果使用echo直接输出"$@"和"$*"作对比,是看不出区别的;但如果使用for循环来逐个输出数据,立即就可以看出区别
实践区别 shell for 循环开发知识
#!/bin/bash 表明用bash解释器 echo "print each param from \ "\$*\"" 打印每个参数来自于$*通过\让他理解这个就是普通字符串,\是转义符, for var in "$*" 定一个任务从$*依次循环拿参数放到var变量里 do echo "$var" 定义每一次循环都打印出来 done echo "print each param from \ "\$@\"" for var in "$@" do echo "$var" 循环$@里面的参数并打印出来 done
代码运行结果:
[root@shiqi ~]# bash qubei.sh shi 180 180 180
print each param from \ $*"
for var in shi 180 180 180
do
echo
done
echo print each param from $@"
shi
180
180
180
$? 上一次命令执行返回状态值 0正确,非0失败
$$ 当前shell脚本的进程号
$! 上一次后台进程的PID
$_ 再次执行之前的命令,最后一次参数
查找方式 man bah
搜索 special parameters
#!/bin/bash # $#获取参数个数 -ne 不等于的情况;&& 并且 [ $# -ne 2] && { echo "must be two args" exit 119 #终止程序运行,且返回119状态码,提供给当前shell的$?变量,若是在函数里免,可以用return 119用法 } echo ok 满足两个参数条件,则输出ok ##################################################################################################### 执行代码结果 [root@shiqi ~]# vim ti.sh [root@shiqi ~]# bash ti.sh yu chao 9 输入了三个参数,大于了设定的两个参数 must be two args [root@shiqi ~]# echo $? 119 [root@shiqi ~]# bash ti.sh yu chao [root@shiqi ~]# echo $? 0 成功输出两参数
###########怎么让程序后台执行
[root@shiqi ~]# nohup ping baidu.com & 1> /dev/null 让pingbaidu后台运行并且日志写入到/dev/null中
[1] 1949
[root@shiqi ~]# nohup: 忽略输入并把输出追加到"nohup.out"
[root@shiqi ~]# ps -ef|grep ping
root 1949 1883 0 15:21 pts/1 00:00:00 ping baidu.com
root 1951 1883 0 15:22 pts/1 00:00:00 grep --color=auto ping
[root@shiqi ~]# echo $! 获取上一次执行的PID
1949
echo "当前的pid是: $$"
[root@shiqi ~]# bash ti.sh yu chao
成功输出两参数
当前的脚本id是: 1955
[root@shiqi ~]# cat shi.sh
#!/bin/bash
echo "当前的路径是:ls"
echo "当前的pid是: $$"
[root@shiqi ~]# echo $_
shi.sh
自定义变量
[root@shiqi ~]# n1=1
[root@shiqi ~]# n2=2
[root@shiqi ~]# n3="$n1"
[root@shiqi ~]# echo $n3
1
[root@shiqi ~]# n4="$n2"
[root@shiqi ~]# echo $n4
2
赋值变量,n1的数值赋值给n3
shell定义的方式
单引号变量,不识别特殊语法
双引号变量,能识别特殊语法
无引号变量,连续的符号可以不加引号,有空格则有歧义最好使用双引号
反引号,引用命令执行结果,等于$()的用法
##单引号
[root@shiqi ~]# name=24
[root@shiqi ~]# name2='${name}'
[root@shiqi ~]# echo $name2 识别不出单引号的特殊语法,将花括号的字符原本的显示出来了
${name}
###双引号
[root@shiqi ~]# name3="${name}"
[root@shiqi ~]# echo $name3 能识别出双引号的特殊语法
24
1.每次调用bash或者sh解释器脚本都会开启一个子shell,因此不保留当前的shell变量,通过pstree命令检查进程数
2.调用source或者点符号,是在当前shell环境加载脚本,因此保留变量,不会产生子shell
3.在linux中反引号,中的命令执行结果会被保留夏利
演示: 1. 开启子shell的执行解释器 [root@shiqi ~]# name=1 [root@shiqi ~]# cat name.sh 父shell的内容 name='西瓜' [root@shiqi ~]# echo $name 1 [root@shiqi ~]# bash name.sh [root@shiqi ~]# echo $name 返回的子shell的结果 1 2. 不开启子shell的执行方法 [root@shiqi ~]# cat name.sh name='西瓜' [root@shiqi ~]# source name.sh 使用source方式 [root@shiqi ~]# echo $name 西瓜
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5xGRtQSs-1665475959817)(C:\Users\陈\AppData\Roaming\Typora\typora-user-images\image-20220923101357621.png)]
思考
[root@shiqi ~]# name=`ls` 反引号是可以在让变量以命令的方式执行
[root@shiqi ~]# echo $name
anaconda-ks.cfg hello.py hello.sh name.sh
环境变量一般指的是export内置命令导出的变量,用于定义shell的运行环境,保证shell命令的正确执行。
shell通过环境变量确定登录的用户名、PATH路径,文件系统等各应用
环境变量可以在命令行中临时创建,但是用户退出shell终端,变量即丢失,如要永久生效,需要修改环境变量配置文件
每个用户都有自己的环境变量配置文件,~/. bash_profile ~/ .bashrc 且以个人配置文件,优先加载变量,读取,以个人的优先生效
当你需要给所有用户都使用某个变量,输入全局即可/etc/profile
[root@shiqi ~]# set |grep ^name
找出电脑中当前shell环境中的全部name开头的变量
[root@shiqi ~]# env |wc -l
24 查看总行数命令
[root@shiqi ~]# set |wc -l
58
[root@shiqi ~]# name="十七"
[root@shiqi ~]# echo ${name}
十七
[root@shiqi ~]# echo $name
十七
[root@shiqi ~]# unset name
[root@shiqi ~]# echo $name
设置只读变量
直接readonly 显示当前系统只读变量
[root@shiqi ~]# readonly password="234"
[root@shiqi ~]# echo $password
234
[root@shiqi ~]# password="233"
-bash: password: 只读变量
bash内嵌了诸多环境变量,用于定义bash的工作环境
[root@shiqi ~]# export |awk -F '[ :=]' '{print $3}' 把空格加冒号等于号的之外的值 HISTCONTROL HISTSIZE HOME HOSTNAME LANG LESSOPEN LOGNAME LS_COLORS MAIL OLDPWD PATH PWD SELINUX_LEVEL_REQUESTED SELINUX_ROLE_REQUESTED SELINUX_USE_CURRENT_RANGE SHELL SHLVL SSH_CLIENT SSH_CONNECTION SSH_TTY TERM USER XDG_RUNTIME_DIR XDG_SESSION_ID
bash多命令执行
[root@shiqi /]# ls /opt ;ls /etc; ls /lib
adjtime cron.daily d
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Gwly9Yyr-1665475959817)(C:\Users\陈\AppData\Roaming\Typora\typora-user-images\image-20220923221617632.png)]
echo 内置命令
eval 执行多个命令
exec 不创建子进程,执行后续命令,且只想完毕后,自动exit
export
read
shift
-n 不换行输出 [root@shiqi ~]# echo 你好;echo 明天 以分号为换行,加上-n则忽略换行的要求 你好 明天 [root@shiqi ~]# echo -n 你好;echo 明天 你好明天 [root@shiqi ~]# echo -n 你好;echo -n 明天 你好明天[root@shiqi ~]# -e 解析字符串中的特殊符号 [root@shiqi ~]# echo "我看你挺好\n的" 我看你挺好\n的 [root@shiqi ~]# echo -e "我看你挺好\n的" 我看你挺好 的 \n 换行 [root@shiqi ~]# echo -e "我看你挺好\n的" 我看你挺好 的 \t 制表符,四个空格 [root@shiqi ~]# printf "你好\t明天\t我是\n" 你好 明天 我是 \r 回车 \b 退格
[root@shiqi ~]# eval ls;cd /tmp anaconda-ks.cfg hello.py hello.sh name.sh nohup.out qubei.sh shi.sh ti.sh [root@shiqi ~]# cat shi.sh #!/bin/bash echo "当前的路径是:ls" echo "当前的pid是: $$" eval systemctl status python;systemctl status firewalld [root@shiqi ~]# ./shi.sh 当前的路径是:ls 当前的pid是: 1976 Unit python.service could not be found. ● firewalld.service - firewalld - dynamic firewall daemon Loaded: loaded (/usr/lib/systemd/system/firewalld.service; enabled; vendor preset: enabled) Active: active (running) since 一 2022-09-26 08:31:11 CST; 7h ago Docs: man:firewalld(1) Main PID: 690 (firewalld)
[shishi@shiqi ~]$ exec date 执行命令后自动退出当前用户
2022年 09月 26日 星期一 15:57:51 CST
[root@shiqi ~]#
$ {变量} | 返回变量值 |
---|---|
$(#)变量 | 返回变量长度字符长度 |
${变量:start} | 返回变量offset数值之后的字符 |
${变量:Start:length} | 提取offset之后的length限制的字符 |
${变量#word} | 从变量开头删除最短匹配的word子串 |
${变量##word} | 从变量开头,删除最长匹配的word子串 |
${变量%word} | 从变量结尾删除最短的word |
${变量%%word} | 从变量结尾开始删除最长匹配的word |
${变量/pattern/string} | 用string代替第一个匹配的pattern |
${变量//pattern/string} | 用string代替所有的pattern |
shell截取字符串通常有两种方式,从指定位置开始截取和从指定字符(子字符串)开始截取。
从指定位置开始截取:
这种方式需要两个参数:除了指定起始位置,还需要截取长度,才能最终确定要截取的字符串。
既然需要指定起始位置,那么就涉及到计数方向的问题,到底是从字符串左边开始计数,还是右边开始计数?答案是shell同时支持两种计数方式
(1)从字符串左边开始计数
如果想从字符串的左边开始计数,那么截取字符串的具体格式如下:
${string:start:legth}
其中,string是要截取 的字符串,start是起始位置(从左边开始,从0开始计数),length是要截取的长度(省略的话表示直接到字符串的末尾)
[root@shiqi ~]# name=yuchao
[root@shiqi ~]# echo ${name:5}
o
[root@shiqi ~]# echo ${name:2:4} ###截取从2开始,元素长度为4
chao
[root@shiqi ~]# echo ${#name} ###返回长度
6
[root@shiqi ~]# echo $name | wc -L 统计字符里面最大的长度 6 [root@shiqi ~]# echo $name | wc -l 统计行数 1 ####wc命令参数用法 [root@shiqi ~]# cat ti.sh | wc -l 10 [root@shiqi ~]# cat ti.sh | wc -L 111 ###expr数值计算命令 [root@shiqi ~]# expr length "${name}" 6 #####awk命令 [root@shiqi ~]# echo "${name}" | awk '{print length}' 9 ####最快的统计速度 root@shiqi ~]# echo ${#name} ###返回长度 6
time 命令,统计命令执行时长 for循环的shell'编程知识 `for 变量 in {序列1~100}` `for number in {1..20}` `do` `你要做什么事` `done` [root@shiqi ~]# for num in {1..20};do echo $num &>/dev/null;done seq生成序列命令,默认空格为分隔符,可以通过"想用的分割数"指定分隔符 [root@shiqi ~]# seq -s ";" 18 1;2;3;4;5;6;7;8;9;10;11;12;13;14;15;16;17;18 [root@shiqi ~]# for num in {1..4};do str=`seq -s ":" 10`;echo $str; done; 1:2:3:4:5:6:7:8:9:10 1:2:3:4:5:6:7:8:9:10 1:2:3:4:5:6:7:8:9:10 1:2:3:4:5:6:7:8:9:10
#####最高统计长度速度{#name} [root@shiqi ~]# time for m in {1..20};do char=`seq -s ":" 10`;echo ${#char} &>/dev/null;done real 0m0.027s 实际运行时间 以这个为主 user 0m0.018s 用户态执行时间 sys 0m0.010s 内核态执行时间 #####wc命令统计 [root@shiqi ~]# time for num in {1..20};do char=`seq -s "shiqi" 10`;echo ${char} | wc -L &>/dev/null;done real 0m0.065s user 0m0.042s sys 0m0.034s ####使用expr统计 [root@shiqi ~]# time for num in {1..20};do char=`seq -s "shiqi" 10`;expr lenght "${char}" &>/dev/null;done real 0m0.063s user 0m0.044s sys 0m0.021s ####使用awk统计 [root@shiqi ~]# time for num in {1..20};do char=`seq -s ":" 10`;echo ${char}|awk '{print lenght(0)}' &>/dev/null;done real 0m0.069s user 0m0.050s sys 0m0.031s
# 从开头删除匹配最短
## 从开头删除匹配最长
% 从结尾删除匹配最短
%% 从结尾删除匹配最长
#指定字符内容截取
a*c 匹配开头为a。中间任意个字符。结尾为c的字符串
a*C 匹配开头为a。中间任意个字符。结尾为C的字符串
##语法
name="yuchao" #该变量的值,有索引,分别是0,1,2,3,4,开始
截取实例
[root@shiqi ~]# name="i an shiqi" 空格也算一个字符
[root@shiqi ~]# echo $name
i an shiqi
[root@shiqi ~]# echo ${name:2:4}
an s
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。