Linux深入探索04-Bash shell
----- 最近更新【2021-12-30】-----
本文目录结构预览:
- 一、简介
- 二、shell 变量
1、查看变量
2、变量类型
3、变量操作
4、系统常见的全局变量 - 三、shell 选项
1、查看 shell 选项
2、设置 shell 选项 - 四、元字符
1、元字符列表
2、引用与转义 - 五、shell 内置命令
1、查看说明
2、常用内置命令 - 六、搜索路径
1、查看搜索路径
2、修改搜索路径 - 七、历史列表
1、查看历史列表
2、调取历史命令
3、调取并修改历史命令
4、搜索历史命令
5、设置历史列表大小 - 八、别名 alias
1、语法
2、创建别名
3、查看别名
4、移除别名
5、不使用别名 - 九、初始化文件
1、文件名称
2、登录 shell 与 非登录 shell
3、初始化文件内容 - 十、参考
一、简介
简单地来说,shell 就是一个 Unix 程序,充当用户界面和脚本解释器,允许用户输入命令以及间接地访问内核的服务。
从功能方面来说:
第一,shell 是一个读取并解释所输入命令的程序。用户每输入一条 Unix 命令,shell 就读取该命令,并指出应该怎么做,所以 shell 是一个命令处理器。
第二,shell 还支持一些类型的编程语言。使用该语言可以编写由 shell 解释的程序,这些程序称为 shell 脚本。
目前比较流行的shell有以下几种 :Bash、Korn shell、C-Shell、Tcsh。
Bash是目前最流行的 shell,本文也是以 Bash 为环境。
如果不知道你目前使用的是哪种 shell,可以使用命令echo $SHELL
来查看。
本文内容可能会比较多,为了方面提前知道有哪些内容,这里先作一个简要的列表:
- shell 变量
--查看变量、变量类型、变量操作、系统常见的全局变量 - shell 选项
--查看 shell 选项、设置 shell 选项 - 元字符
--元字符列表、引用与转义 - shell 内置命令
--查看说明、常用内置命令 - 搜索路径
--查看搜索路径、修改搜索路径 - 历史列表
--查看历史列表、调取历史命令、调取并修改历史命令、搜索历史命令、设置历史列表大小 - 别名 alias
--语法、创建别名、查看别名、移除别名 - 初始化文件
--文件名称、登录 shell 与 非登录 shell、初始化文件内容
二、shell 变量
1、查看变量
上面说的$SHELL
是 shell 的一个全局变量,shell 中还有很多其它的变量。可以使用命令env
或者printenv
去查看全局变量。
使用不带选项或者参数的 set
命令也可以显示所有的 shell 变量以及它们的值。
2、变量类型
根据储存类型,shell变量几乎总是存储一种类型的数据,即字符串。
根据变量的作用域(Scope),shell 变量可以划分为以下三种类型:
- 有的变量可以在当前shell进程及其子进程中使用,这叫做全局变量
- 有的变量仅可以在当前shell进程中使用,这叫做环境变量
- 有的变量只能在函数内部使用,这叫做局部变量(作用域仅为某代码片断(函数上下文))
如果使用export
命令将环境变量导出,那么它就在所有的子进程中也可以使用了,这时称为“全局变量”。
很多书本或网站对环境变量与全局变量的定义都比较模糊,我这里采用一种比较好理解的方式来定义。
3、变量操作
变量通常有4种不同类型的操作,即创建变量、查看变量、修改变量、删除变量。
变量的创建非常简单,使用如下语法就行:
变量名称=变量值 # 注意!等号前后不能有空格。
删除变量:
unset 变量名 ...
例:
[14:59 linux1@noseeu ~]$ MYNAME=Nosee #创建变量(当前shell可用)
[14:59 linux1@noseeu ~]$ echo $MYNAME #查看变量
Nosee
[14:59 linux1@noseeu ~]$ export $MYNAME #导出变量(当前shell及子进程可用)
[15:00 linux1@noseeu ~]$ unset MYNAME #删除变量
[15:00 linux1@noseeu ~]$ echo $MYNAME
[15:00 linux1@noseeu ~]$
注意:
通过 export 导出的变量只对当前 Shell 进程以及所有的子进程有效,如果最顶层的父进程被关闭了,那么这个全局变量也就随之消失了,其它的进程也就无法使用了,这个变量只是临时的。
只有将变量写入 Shell 配置文件中才能达到永久的目的,Shell 进程每次启动时都会执行配置文件中的代码做一些初始化工作,如果将变量放在配置文件中,那么每次启动进程都会定义这个变量。
4、系统常见的全局变量
HISTFILE # 历史列表:用来存储历史命令的文件名称
HISTSIZE # 历史列表:用来存储历史命令的最大数目
HOME # home目录
HOSTNAME # 计算机名称
LOGNAME # 当前用户标志(用户名)
PATH # 程序搜索目录
PS1 # shell提示
PWD # 当前工作目录
SHELL # shell类型
TERM # 终端类型
USER # 当前用户标志(用户名)
三、shell 选项
在Bash shell中,当我们需要控制 shell 行为的各个方面时,则可以使用shell 选项。
shell 选项就像 on/off 开关一样。当打开一个选项时,就说设置了这个选项;当关闭这个选项时,就说复位了这个选项。
shell 选项或者是 off 或者是 on ,它们不需要创建。
1、查看 shell 选项
可以使用命令set -o
或者set +o
来查看所有 shell 选项,两种查看方式只是在显示格式上不一样。
set -o
命令以一种易于阅读的方式显示(人类可读)
set +o
命令显示的输出适合用作 shell 脚本的数据(机器可读)
选项介绍:
选项 | 短名称 | 含义 |
---|---|---|
allexport | -a | 导出随后定义的所有变量和函数 |
braceexpand | -B | 启用括号扩展(生成字符模式) |
emacs | 命令行编辑器:Emacs模式,关闭vi模式 | |
hashall | -h | 查找到命令时(记住)的命令哈希位置 |
hisexpand | -H | 历史列表:启用!风格替换 |
history | 历史列表:启用 | |
ignoreeof | 忽略eof信号^D;使用exit或logout退出shell | |
minitor | -m | 作业控制:启用 |
noclobber | -C | 不允许重定向的输出替换某个文件 |
notify | -b | 作业控制:当后台作业结束时立即通知 |
vi | vi模式:立即处理每个键入的字符 |
使用命令 shopt
可以查看更多的 shell 选项。
2、设置 shell 选项
语法:
set -o option # 打开shell选项(开启)
set +o option #复位shell选项(关闭)
注意,这里的-o
表示开启一个选项,+o
表示关闭一个选项。
1)如,我要开启某个选项(选项noclobber
表示不允许重定向的输出替换某个文件)
则可以:
set -o noclobber # 开启该选项
或者:
set -C
关闭该选项则这样:set +o noclobber
或set +C
2)忽略eof信号^D
[21:34 linux1@noseeu ~]$ set -o ignoreeof
# 此时我再按 <Crlt>-D 组合键
[21:34 linux1@noseeu ~]$ Use "logout" to leave the shell.
设计 shell 的程序员们知道人们会如何使用 shell,因此在大多数情况下,默认的 shell 选项就可以满足要求。这意味着我们极少需要云修改 shell 选项。
四、元字符
在shell中,有许多字符拥有它特殊的含义,我们称这样的字符为元字符。如;
(分号)、\
(反斜杠)、.
(点号),抽象一点的如按键<Space>
、<Tab>
、<Enter>
也是使用了元字符。
1、元字符列表
字符 | 名称 | 作用 |
---|---|---|
| | 管道 | 命令行:创建一个管道线 |
< | 小于 | 命令行:重定向输入 |
> | 大于 | 命令行:重定向输出 |
() | 圆括号 | 命令行:在子shell中运行命令 |
# | hash、pound | 命令行:注释 |
; | 分号 | 命令行:用于分隔多条命令 |
` | 反引号 | 命令行:命令替换 |
~ | 波浪号 | 文件名扩展:插入home目录的名称 |
? | 问号 | 文件名扩展:匹配任意一个字符 |
[] | 方括号 | 文件名扩展:与一组字符中的字符匹配 |
* | 星号 | 文件名扩展:匹配0个或多个字符 |
! | 叹号、bang | 历史列表:事件标记 |
& | 和号 | 作业控制:在后台运行命令 |
\ | 反斜杠 | 引用:下一个字符转义 |
' | 单引号 | 引用:取消所有的替换 |
" | 双引号 | 引用:取消大部分替换 |
{} | 花括号 | 变量:确定变量名称的界限 |
$ | 美元符号 | 变量:用变量的值替换 |
空格符 | 空白符:在命令行中分隔单词 | |
制表符 | 空白符:在命令行中分隔单词 | |
新行字符 | 空白符:标记一行结束 |
以上元字符列表展示的就是元字符在shell中的常用作用。
2、引用与转义
有时候,我们希望按字面上的含义使用元字符(而不是使用其特殊含义),这时我们必须告诉shell按字面意思解释字符。这样做时,可以称其为引用字符。
字符的引用有3种方法:使用反斜杠、一对单引号或者一对双引号。
当使用反斜杠引用单个字符时,我们称反斜杠为“转义字符”。
如:
echo It is warm\; come on.
上面例子中,;
(分号)在shell中有特殊的含义,如果我们想原样输出则必须转义。这时可以说“使用反斜杠转义了分号”,或者可以说“使用反斜杠引用了分号”。
当元字符少时,上面的方法没有什么问题。但是当元字符多的时候,我们就需要用到单引号或者双引号了。
1)强引用(单引号)
单引号里面的所有元字符都会被转义,也就是所有元字符都会原样输出。
如,下面的$
会被转义,$NAME
会原样输出:
linux1@noseeu:~$ echo 'My name is $NAME'
My name is $NAME
2)弱引用(双引号)
双引号引用时,会保留$
(美元符号)、`
(反引号)、\
(反斜杠)的特殊含义。
如:
linux1@noseeu:~$ echo "My name is $NAME"
My name is Chan
[22:04 linux1@noseeu ~]$ echo "now is `date`."
now is Sun 26 Dec 2021 10:04:24 PM UTC.
上面的$
不会被转义,$NAME
会被替换为NAME
的实际值;`
也不会被转义,date
会被当作嵌入命令优先执行。
注:反斜杠是所有引用中最强的,所以它甚至可以引用新行字符(<Enter>
)。
如,
linux1@noseeu:~$ echo hi \
> nosee.
hi nosee.
linux1@noseeu:~$ date;\
> cal
Sun 26 Dec 2021 05:28:01 PM UTC
December 2021
Su Mo Tu We Th Fr Sa
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
在这里新行字符(<Enter>
)失去了它的特殊含义,所以这时它并不是一行结束的信号了,意味着后面输入的内容都是接着上一行的。
五、shell 内置命令
当在shell中输入命令时,shell会将命令进行解析,然后决定如何处理命令,其中有两种可能。一些命令在shell的内部,这意味着shell可以直接解释它们,这些命令是内部命令,称为内置命令。其他所有命令都是外部命令,即必须独自运行的独立程序。
当输入内置命令时,shell在自己的进程内运行该命令(不创建新的进程)。当输入外部命令时,shell将搜索合适的程序然后以一个单独的进程运行该命令(创建一个子进程)。
查看某一条命令是不是内置命令的快捷方法是使用type
。如:
linux1@noseeu:~$ type time set date type
time is a shell keyword
set is a shell builtin
date is hashed (/usr/bin/date)
type is a shell builtin
可以看出,time、set、type都是shell的内置命令,而date是外部命令。
1、查看说明
几乎所有的Unix程序在发行的时候都提供有说明明书页,即可以用man
或者info
去查看它们的说明。但内置命令不是一个单独的程序,它们是shell的一部分,每种shell都会提供大量的命令,所以每个内置命令都开发一个单独的说明书页是不现实的。
其实,所有的内置命令都记录在shell的说明书页中,即你可以使用man bash
去查看。但是shell的说明书页都非常长,可能需要使用搜索才能找到所需的内容(可以使用apropos
命令或者man -k
命令进行搜索)。
还有一个方法,就是使用help
命令也可以查看内置命令的说明,如:help unset
linux1@noseeu:~$ help unset
unset: unset [-f] [-v] [-n] [name ...]
Unset values and attributes of shell variables and functions.
...
...
Exit Status:
Returns success unless an invalid option is given or a NAME is read-only.
使用不带参数的help
命令,可以显示一个所有内置命令的摘要列表。如下图:
使用help -s
命令可以查看某个内置命令的语法:
linux1@noseeu:~$ help -s set
set: set [-abefhkmnptuvxBCHP] [-o option-name] [--] [arg ...]
2、常用内置命令
alias # 为指定命令定义一个别名
echo # 将指定字符串输出到STDOUT
exit # 强制 shell 以指定的退出状态码退出
export # 将变量导出到全局变量
fc # 从历史记录中选择命令列表
help # 显示帮助说明
history # 显示命令历史记录
kill # 向指定的进程 ID(PID) 发送一个系统信号
pwd # 显示当前工作目录的路径名
set # 设置并显示环境变量的值和 shell 属性
shopt # 打开/关闭控制 shell 可选行为的变量值
type # 显示指定的单词如果作为命令将会如何被解释
unset # 刪除指定的环境变量或 shell 属性
六、搜索路径
大部分命令都不是 shell 内置的,那么 shell 必须查找出合适的程序来执行。那么 shell 在哪里查找外部命令?
shell 通过查找变量 PATH
来获得一系列目录名称,然后在这些目录下寻找对应的程序,这些目录名称就是我们所说的搜索路径。
1、查看搜索路径
搜索路径是包含所有外部命令的程序的目录列表,使用命令echo $PATH
可以查看 搜索路径。
[21:31 linux1@noseeu ~]$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
搜索顺序:
当 shell 在查找外部程序时,它在搜索路径中会按指定顺序逐个检查目录,进到找到期望的外部命令时,它就停止搜索并执行程序。
2、修改搜索路径
修改搜索路径的基本思想就是将修改PATH
变量的命令放到登录时自动执行的初始化文件中。
PATH
的值就是一个包含若干目录名称的字符串,各个目录名称用:
(冒号)隔开。
如我有一些自定义的程序放在 ~/bin 目录,那么我可以这样设置:
export PATH="$PATH:$HOME/bin"
一般修改 PATH
的值我们都是在原有的路径上再加上我们想要添加的路径。
七、历史列表
在输入命令时,shell 会将命令保存到所谓的历史列表中。然后我们可以采用不同方式访问历史列表,调取前面的命令,然后再对命令进行修改,并重新输入命令。
1、查看历史列表
最简单的查看历史列表的办法就是使用<Up>
和<>Down
键,但是这个方法每次只能查看一条命令。
还有一个更强大的命令,可以查看全部或者部分历史命令,就是使用history
或者fc
命令。
在历史列表中,每条命令称为一个事件,而每个事件都有一个内部编号,称为事件编号。历史列表的主要功能就是它可以基于事件编号调取命令。
查看历史列表:
[23:12 linux1@noseeu ~]$ fc -l
...
931 echo "'now is `date`."
932 help fc
933 fc-l
[23:12 linux1@noseeu ~]$ history
1 sudo -i
2 exit
...
934 fc -l
935 history
每条命令前面的数字就是事件编号。
2、调取历史命令
如我们想再次运行932号命令,可以使用fc -s 932
或者!932
。
[23:14 linux1@noseeu ~]$ fc -s 932
help fc
fc: fc [-e ename] [-lnr] [first] [last] or fc -s [pat=rep] [command]
Display or execute commands from the history list.
...
Exit Status:
Returns success or status of executed command; non-zero if an error occurs.
[23:22 linux1@noseeu ~]$ !932
help fc
fc: fc [-e ename] [-lnr] [first] [last] or fc -s [pat=rep] [command]
Display or execute commands from the history list.
...
Exit Status:
Returns success or status of executed command; non-zero if an error occurs.
如果只是希望输入最近上一条命令,则可以不带事件编号:fc -s
或者!!
3、调取并修改历史命令
shell 允许在重新执行历史命令之前对命令进行小的修改,语法如下:
fc -s pattern=replacement number
!number:s/pattern/replacement
例:
937 vim sh_test1
[23:34 linux1@noseeu ~]$ fc -s sh_=Sh 937
vim Shtest1
[23:35 linux1@noseeu ~]$ !937:s/sh_/Sh
vim Shtest1
如果只是想修改上一条输错的命令,还可以这样:
[23:39 linux1@noseeu ~]$ datw
Command 'datw' not found.
[23:39 linux1@noseeu ~]$ ^w^e
date
Sun 26 Dec 2021 11:40:12 PM UTC
[23:40 linux1@noseeu ~]$
记住,这个方法仅适用于对上一条历史命令修改。
4、搜索历史命令
bash 还提供了一个非常方便的历史命令搜索方式,即使用<Ctrl>-R
(^R)。
如我需要调取一条设置PS1变量的命令,查历史列表又觉得麻烦。这时我就可以按下<Ctrl>-R
键,然后输入关键词PS:
linux1@noseeu:~$
(reverse-i-search)`PS': PS1="\[\033[0;32m\][\A \u\[\033[0;33m\]@\H \w]$ \[\033[0m\]"
如果显示出的命令是你想要的,直接按回车就可以执行了:
linux1@noseeu:~$ PS1="\[\033[0;32m\][\A \u\[\033[0;33m\]@\H \w]$ \[\033[0m\]"
[23:54 linux1@noseeu ~]$
如果看到的不是你想要的命令,可以继续按<Ctrl>-R
搜索下一个。
5、设置历史列表大小
Bash shell 将历史列表存储在一个文件中,所以下次登录时还是可以继续使用。为了避免历史列表太多,shell 允许通过设置一个变量来设置历史列表的大小。
查看 shell 默认设置:
linux1@noseeu:~$ set | grep HIST
HISTCONTROL=ignoreboth
HISTFILE=/home/linux1/.bash_history
HISTFILESIZE=2000
HISTSIZE=1000
如我们要修改history
命令所展示的历史列表条数:
linux1@noseeu:~$ export HISTSIZE=10
八、别名 alias
别名就是赋予一条命令或者一列命令的名称。可以将别名作为缩写,或者使用别名创建已有命令的自定义变体。
1、语法
Define or display aliases.
alias: alias [-p] [name[=value] ... ]
2、创建别名
我们经常会使用ls -al
来查看文件列表,为了方便可以如下定义别名:
alias ll='ls -al'
当一条命令中包含有空格或元字符时,记得要使用引号包围。
linux1@noseeu:~$ alias mytime='date; cal'
linux1@noseeu:~$ mytime
Mon 27 Dec 2021 01:01:56 AM UTC
December 2021
Su Mo Tu We Th Fr Sa
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
3、查看别名
当需要查看某个别名的含义时,可以这样:
linux1@noseeu:~$ alias mytime
alias mytime='date; cal'
或者使用type
命令:
linux1@noseeu:~$ type mytime
mytime is aliased to `date; cal'
查看所有别名:
linux1@noseeu:~$ alias
alias alert='notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l='ls -CF'
alias la='ls -A'
alias ll='ls -al'
alias ls='ls --color=auto'
alias mytime='date; cal'
4、移除别名
语法:Remove each NAME from the list of defined aliases.
unalias [-a] name [name ...]
例:
linux1@noseeu:~$ unalias mytime
linux1@noseeu:~$ mytime
mytime: command not found
5、不使用别名
如ls
命令,很多 linux 会默认就在配置文件中设置了ls --color=auto
,这时你就会在不知情的情况下使用了别名。如果你不想使用使用别名,可以在命令前面键入一个\
,告诉 shell 不使用任何别名,如\ls
。
九、初始化文件
以上所说的所有设置都是只有当前shell生效,注销然后再登录之后那些设置都不存在了。如果你想在你下次登录时还可以继续使用你的设置,则需要把你的设置添加到初始化文件中。
Bash shell 的初始化文件包括两个,即登录文件和环境文件。
初始化文件存放着所有希望在每次登录时自动执行的命令,而环境文件存放着所有希望在新 shell 启动时自动执行的程序。
为了提供更多的功能,Bash shell 还提供了注销文件,用于存放注销登录时自动运行的命令。
1、文件名称
初始化文件的名称在不同的系统中可能会稍有不同,但基本都是以下这种:
执行环境 | 文件名称 |
---|---|
登录文件 | .bash_profile、.profile、.bash_login |
环境文件 | .bashrc |
注销文件 | .bash_logout |
文件存放的目录都为用户目录,即:/home/用户名
注:
系统启动的时候会先执行.profile
然后执行.bashrc
,所以如果这两个文件存在相同的配置的话,前面的会被后面的覆盖。
2、登录 shell 与 非登录 shell
1)登录 shell
在任何时候,如通过ssh连接登录到远程主机,或者使用
登录 shell 的初始化会执行登录文件(.profile)与环境文件(.bashrc)。
2)非登录 shell
当打开一个 shell 窗口不需要登录认证时,如在一个已登录的 shell 窗口输入 bash
打开一个新 shell,或者在桌面环境简单地打开一个终端窗口,等,我们称这类 shell 为 非登录 shell。
非登录 shell 只执行环境文件。
3、初始化文件内容
shell 的初始化文件一般包含下述内容:
1)创建或者修改环境变量的命令
2)执行所有一次性操作的命令
3)合理的注释
4)等
如:
# 设置环境变量
HISTSIZE=50
HISTFILESIZE=1000
# 设置文件创建掩码,控制新创建文件的默认权限
umask 077
# 设置别名
alias ll='ls -alF'
alias la='ls -A'
alias l='ls -CF'
# 设置默认的分页程序(需要调用分页程序显示数据时就会调用该程序,如 man 命令)
export PAGER=less
# 设置分页程序的默认选项,相当于:alias less='less -CMs'
export LESS='-CMs'
# 查看命名为`.bashrc`的文件是否存在,如果存在,则运行这个文件
if [ -f "$HOME/.bashrc" ]; then
. "$HOME/.bashrc"
fi
十、参考
书箱:《Unix & Linux 大学教程》第11-14章 (美)Harley Hahn 著 张杰良 译
博客: 命令行界面 (CLI)、终端 (Terminal)、Shell、TTY的区别
SegmentFault: Linux TTY/PTS概述
作者:四月不见
出处:https://www.cnblogs.com/nosee/p/15842462.html
本文版权归作者所有,转载请注明原文链接。