关于shell
- 内核是Unix/Linux操作系统的心脏,内核主要是负责***控制硬件,管理内存和调度任务***
- shell是用户和操作系统之间的一座桥梁,用户可以利用shell实现对Unix/Linux操作系统及其内核的控制和操作
- shell已经发展成为一种解释性编程语言,他不仅包含大量的命令以实现操作系统的对话,还可以实现变量定义,条件判断,循环判断,函数调用等功能,我们可以利用shell来实现很多复杂的业务逻辑。
- 当我们打开一台装有Unix/Linux操作系统的电脑时,输入用户名密码登陆成功后,系统便会启动一个shell,他是一个***交互式的界面***,会等待我们输入指令,就像这样:
- 当我们输入了一条指令后,shell会经过一系列的处理环节然后执行,并为我们返回执行的结果
- shell脚本?
- 交互式的shell并不能满足一些要求,他们想把工作和任务通过自动化方式来完成,所以会出现shell脚本
- 把多个shell命令按照一定的逻辑写到一个文件中时,这个文件就可以叫做"shell脚本文件"。执行这样的脚本,就可以实现一部分工作的自动化。
- 看本电脑的shell
- 查看当前系统装了哪些shell?
cat /etc/shells
- 这个文件中记录了当前系统中安装了哪些种类的shell
*
- 查看系统当前使用的是什么shell?
echo $SHELL
- 想体验别的shell
- 先定位到该shell的位置
which zsh
- 使用-s选项更改登录shell的类型
chsh -s shell的位置
- 先定位到该shell的位置
- 查看当前系统装了哪些shell?
chsh 展示和修改我们系统的***登录shell***
-
功能:
- 展示和修改我们系统的***登录shell***
- 没有参数
chsh
- 参数-s
- 指定系统登录时的shell
-
奇怪的点:
- 原因:
- 虽然执行了zsh,但是所谓的"当前的shell"是一个大环境的概念,是针对一个已登录的用户而言的。我们执行zsh***只是启动了一个zsh的解释其程序而已***,并没有改变大环境。
- 做出改变:
* - 这时候执行
echo $SHELL
发现输出没有变化。 - 原因:
- chsh改变的是***我们登录shell的配置***。我们必须退出再重新登录shell。
- 原因:
-
chsh -s修改了哪里?
- 修改的是
/etc/passwd
文件中和我们所登陆的用户名相对应的那一行
* - 当系统重启的时候,Linux就会读取这一命令来启动新的shell
- 修改的是
export 设置或显示环境变量
参数 | 含义 |
---|---|
-n | 删除指定的环境变量 |
-p | 列出所有的环境变量和不加参数一样 |
-
当终端上输入
export
会出现什么?*
- 输出内容就是bash的所有环境变量
-
有几个的区别
-
env,set,declare,export可以显示shell中的变量,这四个有什么区别呢?
-
shell的变量可以分为“环境变量”和“自定义变量”
-
区别:作用范围不同
-
变量名称 含义 环境变量 可以在进程的子进程中继续有效 自定义变量 无法延伸到进程的子进程中
-
-
名称 env 显示当前用户的环境变量,不会显示其自定义变量 export 和env相同,不过该命令的输出是按变量名进行排序的 declare 显示当前shell中定义的所有变量,包括用户的环境变量和自定义变量,按变量名排序 set 功能和declare一样 -
env和export的区别:(环境变量)
*
-
declare 和 set(环境变量和自定义变量)
-
-
设置环境变量:
-
echo $PATH
打印环境变量- $PATH变量的值是由多个路径所组成的,并且用冒号进行了分隔。
- 路径的作用:
- 当用户在Linux系统中直接输入一个命令,而没有指定其绝对路径,Linux就会一次进入$PATH变量所指定的各个路径中,去寻找是否存在此命令,如果找到,就执行该命令;如果没有就直接退出并提示没有找到该命令。
-
将路径追加到$PATH变量中去
export PATH=$PATH:/home/lala
- 若为
PATH=$PATH:/home/lala
会变成什么?
- 若为
-
怎样设置环境变量?(三种方法)
-
使用
export
命令export PATH=$PATH:/home/lala
- 请注意:使用export设置的变量都是临时变量,也就是退出当前的shell,就会恢复原样
-
修改
/etc/profile
- 在文件中假如光标所在的一行代码
- 可以使用
source /etc/profile
或者. /etc/profile
在不重新启动系统的情况下使修改的内容有效。
- 在文件中假如光标所在的一行代码
-
修改
.bashrc
文件使在用户shell下生效vim /root/.bashrc?
export PATH=$PATH:
- 可以使用
source
或者.
在不重新启动系统的情况下使修改的内容有效。
-
-
-
export的作用?
-
使用export设置的变量是环境变量,没有使用export设置的变量是自定义变量
*
- 当进入一个bash子进程后,var1变量有效,var2变量无效,输出来什么也没有
- 可以得出结论:环境变量可以在其进程的子进程中继续有效,而自定义变量则无效。
-
这个是怎么回事?
- 使用
export
的变量都是临时变量,如果想让他变成永久的,可以按照上面设置PATH的2,3方法。
-
-
对比两个命令:
- 如果命令中少了 PATH的内容,而 加上则是表明在原来内容的基础上增加。
read命令 倾听标准输入或文件输入,把信息存放到变量中
选项 | 含义 |
---|---|
-p | 显示提示语 |
-t | 控制时间 |
-s | 输入时不显示内容 |
-r | 将转义符变成普通字符 |
首先写两个shell脚本来观察一下read的用法
- 显示一个变量的
-p
:使用来显示提示语的
- 显示两个变量的
- read会以空格来分割用户的输入内容,并把输入内容分别存放到后面的变量中。
- read可以指定多个变量。如果输入和期望的变两个数不等:
输入的数据少与变量的个数,多余的变量不会获取到数据,变量值为空
如果多,炒出来的数据都付给最后一个变量
如果read后面没有变量,但是我们键盘输入了,那么输入的数据会放在?
$REPLY
这个环境变量中去测试一下:
如果用户长时间不输入东西呢?会有时间限制吗?
使用-t来控制时间
如果输入的东西向暗纹展示呢?
使用-s使用户在输入的时候屏幕上不显示任何消息
以上是通过写一个脚本来实现read的用法,那直接打出来可以吗?
sure!!!
以上都是键盘输入,那么来自文件的是怎么回事呢?
使用-u
- 通过
exec 3<a
生成了编号为3的文件描述符,接着通过read -u 3 var
来读文件的内容,最后通过exec 3<&-
关闭了3号文件描述符
使用管道
- 使用
cat a|while read line
通过这样的方式来遍历a文件的内容,并按行赋值给变量line
仔细观察,最后结果应该是Line no is 3,为什么会出现Line no is 1?
进一步探索吧
原来最后的count是最初的,当do里面改变了count后并没有改变实质?
是因为***管道***导致的。管道***两边一般需要新建进程,当执行完while语句后,新进程就结束了。而脚本里的count是新进程中的自定义变量,进程结束后该变量也消失了(自定义变量的生命周期结束)。***当脚本执行echo时,现实的counnt变量是脚本中第一行定义的变量的值,而不是while语句中的那个count变量了。
使用重定向
将转义字符变成普通字符
-r
expr 简单计算器
打印表达式的值到标准输出
用法
- 用空格隔开每个项
- 用反斜杠( \ )放在shell特殊字符上面
*
*- 对包含空格和其他特殊字符的字符串用括号括起来
- 适用范围
- 可以实现数字的四则运算
- 字符串的运算
tmux
tmux “Terminal MultipleXer” “终端复用器”
让人们通过一个窗口操作多个会话的工具
-
适用范围
- 做Linux服务运维的时候,用scp进行服务期间的大文件网络传输。一般需要很长时间。如果工作电脑出现断网或者断电会导致远程连接工具无法与服务器通信是的所控制的数据传输因此中断。
- 一些大型的开发项目的代码的编译过程往往需要很长时间
- 多个窗口切换
- 分屏管理工具,不要手动调整他们的大小和位置
-
启动tmux
tmux 或者 tmux new -s roclinux
-
-s是session的缩写
-
启动了一个全新的tmux会话(tmux session),并把这个会话起名为roclinux
-
tmux环境:
-
-
创建一个新的窗口
-
Crtl+B然后松开
-
再按c键
下面1:bash* 新的window
-
*表示:
当前处于活跃状态的窗口
,即哪个窗口处于可操作状态- 解释0:bash* 和0:bash- 1:bash*
-
-
在窗口间切换
- Crtl+B
- 按数字(想要切换到几号窗口就按几号)
-
可以让远端服务器的命令脱离用户自己的电脑来执行还可以随时召唤回来,继续进行操作和查看
-
watch -n 2 free
-
每隔2秒更新一次内存使用状态,不输入Ctrl+C就不会退出
-
电脑断网但不想中断服务器上正在执行的watch命令怎办?
- Crtl+B
- d
此时:
输入
tmux a
或者tmux a -t roclinux
(-t roclinux说明窗口的名称)此时就继续运行刚才查看内存使用状态的watch命令
-
-
alias 定义别名
设置的别名,系统重启后本次设置的别名不再生效。如果要让设置永久生效,请查看并修改.profile或.cshrc文件
将所有别名的设置方案加入到($HOME)目录下的
.alias
文件中(如果系统中没有这个文件可以自己创建一个),然后在.bashrc
文件中增加一段代码
参数 | 含义 |
---|---|
不加参数 | 显示当前系统下已经定义的别名 |
name=value | 设置name的别名是value |
name | 查看name是否被别名为什么 |
-
注意
- =前后不能有空格
- 如果value中有空格或tab,value一定要用引号括起来
- 在终端输入一个命令后,按下
Ctrl+Alt+e
组合键后,假如设置了别名,那么别名自动会变成实际的命令
-
如何执行命令本身而非别名
- 使用命令的绝对路径
- 切换到命令所在的目录,执行
./command
- 在命令前使用反斜杠( \ )
* * 不知道为什么?
-
定义别名的过程中单引号和双引号的区别
- 看一张图:
- 实质:
- 看一张图:
-
这个为什么?
- Linux shell有交互式和非交互式两种工作模式。日常使用***shell输入命令得到的结果的方式是交互式的,shell脚本使用的是非交互式的***
- 在交互模式下,shell的alias扩展功能是打开的,因此我们可以键入自己定义的alias别名来执行对应的命令
- 在非交互模式下alias扩展功能默认是关闭的,此时仍然可以定义alias别名,但是是shell不会将alias别名扩展称对应的命令,而是将alias别名本身当成命令执行,如果shell内置命令和PATH中均没有和alias别名同名的命令,则shell会抱怨找不到指定的命令。
- 怎样在非交互模式下启用alias扩展?
- 使用shell内置的
shopt
命令来开启alias别名扩展选项expand_aliases- 既然已经开启了为什么还是不行?
- 使用shell内置的
* 实验一:
* 可以看出失败的原因:虽然在shell中expand_aliases是on,但是当执行test.sh时会***产生一个新的进程去执行***,这个新的进程中expand_aliases却是off的状态。
* 实验二:
* 实验三:
* alias竟然没有输出,这还是执行程序时新生成进程的问题。因该是脚本中的alias没有继承shell中alias的设置内容
* 好吧,那就给出方法吧:(我的电脑上面不行不知道原因)
* --login使得执行脚本的子shell成为一个login shell,login shell会读取系统和用户的profile及rc文件,因此用户自定义的.bashrc文件中的内容将在执行脚本的子shell中生效。
* alias别名只在当前shell有效,不能被子shell继承,也不能像环境变量一样export。可以把alias别名定义写在.bashrc文件中,这样如果启动交互式的子shell,则子shell会读取.bashrc,从而得到alias别名定义。但是执行shell脚本时,启动的子shell处于非交互式模式,是不会读取.bashrc的。
unalias 删除别名
参数 | 含义 |
---|---|
-a | 删除所有别名 |
name | 删除这个name的别名 |
history 显示历史指令
参数 | 作用 |
---|---|
无参数 | 曾经执行过的命令 |
-c | 消除记录(重新启动记录还在障眼法) |
-w | 覆盖原有的history文件 |
-n | 显示n个最近的指令 |
-d数字 | 删除该数字代表的命令 |
如果想知道命令什么时候执行的
使用下面的
两个问题:
- 系统怎么知道我们在什么时间执行了那些命令?
- 屏幕上出现的都是一样的时间,为什么?
- 当我们重新启动系统后,执行
cat .bash_history
- 看到文件中的#154…这种格式的字符串了?这些就是命令执行的时间戳,通过这些标记,history就能正确显示命令的执行时间了。
- 第二个:
- 因为开始的命令执行时并没有开启“时间戳记录功能”,在后面需要显示时间戳时,他们只能取距离他们最近的有时间记录的那个时间点作为他们的时间戳。
重复上一条命令
- 使用
向上方向键
,并回车执行- 输入
!!
并回车执行- 输入
!-1
并回车执行- 输入
Ctrl+P
组合键并回车执行
想执行以前执行过得某条命令
!数字
Ctrl+R
搜索曾经的命令
-c
- 特点:
- 删除的只是Linux系统内存中的历史命令,当shell退出时就不会有历史命令追加到文件.bash_history中。但是重新登录shell时,shell便会加载文件.bash_history,该文件中存储着曾经输入的历史命令。
- 想要彻底删除历史命令
history -c
和history -w
- 特点:
history的配置
设置历史记录时间
export HISTTIMEFORMAT='%F %T'
- 有个空格,这样在显示日期和命令之间会有个空格分隔。
控制历史命令记录的总个数
export HISTSIZE=1000
设置内存中的history命令的个数export HISTFILESIZE=1000
设置文件中的history命令的个数更换历史命令的存储位置
- 历史命令会存储在
~/.bash_history
文件中export HISTFILE=~/history.log
其他
使输出的命令在history命令输入出后不显示在屏幕上
- 第一种
export HISTCONTROL=ignorespace
- 输入重要命令时再输入命令前加上空格
- 第二种
export HISTIGNORE=*
- 恢复命令的记录
export HISTIGNORE=
输入这个命令后系统又恢复正常了,输入的命令又能被正常记录了。
xargs 从标准输入中读取内容,并将此内容传递给他要协助的命令,并作为那个命令的参数来执行
参数 | 含义 |
---|---|
-0 | 将分割符变为NULL并将单引号双引号反斜线变普通 |
-d | 指定一个符号为分隔符 |
-p | 传送参数前确认一下 |
-n数字 | 每次只处理数字个参数 |
-E东西 | 碰到某个特定的命令参数时,要求xargs立即终止并退出 |
execute arguments的缩写
x(乘号) args(参数)
来展示一下xargs的用法
xargs将echo的输出作为自己的标准输入,并将其传递给了ls命令作为ls命令的参数来执行
结合管道
- 结论:
- cat命令不能从标准输入接收参数
- 管道可以实现将前面的标准输出作为后面的标准输入
- 管道不能实现将前面的标准输出作为后面的“命令参数”,但是我们可以结合args来
*
注意的点:
- xrags的标准输入中出现的“换行符 空格 制表符”都将被空格取代。xargs默认的分隔符是空格
- 怎样将默认的分隔符变一下?
-0
允许将NULL作为分隔符,还会将单引号,双引号,反斜线默认为普通字符-d
指定任何一个符号作为分隔符
-p
传参数前和我们确认一下(y/n)
-n
-E
time 可以测量运行时间还可以测量内存,I/O使用情况
time命令是用来测量Linux程序执行时间的命令
测量命令的执行时间或者给出系统资源的使用情况
date命令是显示系统时间的命令
名称 | 含义 |
---|---|
real | 从进程开始执行到完成所耗费的CPU总时间。该事件包括***进程执行时实际使用的CPU时间,进程耗费在阻塞上的时间(等待完成I/O操作),其他进程所耗费的时间***(Linux是多进程系统,该命令在执行过程中可能有别的进程抢占CPU) |
user | 进程执行用户态代码所耗费的CPU时间。改时间仅指该进程执行时实际使用的CPU时间,不包括其他进程所使用的时间和本进程阻塞的时间 |
sys | 该进程在内核态运行所耗费的CPU时间,即执行内核系统调用所能耗费的CPU时间 |
三个误区
- real_time=user_time+sys_time
- real_time是包含了其他进程的执行时间和进程阻塞时间的,但是usr_time+sys_time不包括其他进程的执行时间和进程阻塞时间的。因此real_time>user_time+sys_time是有可能的
- real_time>user_time+sys_time
- 在单核CPU系统中这个关系是成立的,但如果是在多核CPU下,不成立。多核CPU可以并行地处理多项事务,就像一个工作原来是一个CPU核去做,现在是两个CPU核去做,那么完成同样的工作花费的时间是user_time+sys_time,而两个人并行却能在更短的时间完成耗时为real_time,因此出现real_time<user_time+sys_time
实行find命令时
为什么会不同?
- find命令在第一次执行后,系统会对一些文件做缓存,第二次执行后,就正好用到了这些缓存中的数据,因此执行速度就会变快很多
-
想查看一条命令执行了多长时间
*
-
举了这么多例子,为什么和功能呢个描述的不符?
- 上面用的time命令是
Bash内置的命令
,功能比较弱,而更强大的time命令隐藏在/usr/bin目录下
。在使用的时候一定在前面加上\
,表示这个time不是Bash内置的time命令。
*
- 最后两行打印了很多指标数据,可以使用
-v
选项,这样可以打印出更详细的信息
注意有一行Elapsed time是0:0.00?
- 因为在time命令的输出中,Elapsed time是通过系统调用gettimeofday获取到的结束时间和起始时间相减得到的。因此,time对于运行时间较短的任务计时时会产生一定的误差。time命令输出的时间同级精度基本在10毫秒级
- 上面用的time命令是
-
time命令输出指标
-
time命令可以显示的资源共有三大项:时间,内存和I/O
- 时间
- 内存
-
-
I/O
sleep 休眠 使系统进入休眠状态
–: | 含义 |
---|---|
数字字母(字母是smhd) | 睡眠数字字母单位 |
-
让系统休息
-
sleep的默认单位:秒
字母 | 含义 |
---|---|
s | 秒 |
m | 分钟 |
h | 小时 |
d | 天 |
- sleep命令只能保证10ms级别的精度控制,对于10ms的睡眠时间存在误差的
- 默认情况下sleep的进程是不占用CPU时间的