shell和BASH简介
shell
我们必须要透过『 Shell 』将我们输入的指令与 Kernel 沟通,好让 内核 可以控制硬件来正确无误的工作
优势
- 几乎各家 distributions 使用的 bash 都是一样的!如此一来, 你就能够轻轻松松的转换不同的 distributions
- Linux 的管理常常需要透过远程联机,而联机时文字接口的传输速度一定比较快, 而且,较不容易出现断线或者是信息外流的问题
- 便于管理主机
BASH
/bin/bash 是Linux的预设shell。
功能
命令编修能力 history
在指令列按『上下键』就可以找到前/后一个输入的指令。而在很多 distribution 里头,默认的指令记忆功能可以到达 1000 个。这些指令被放在.bash_history
命令和文件补全功能
就是之前提到的tab键的功能,tab再指令的不同位置作用是不一样的:
- [Tab] 接在一串指令的第一个字的后面,则为命令补全
- [Tab] 接在一串指令的第二个字以后时,则为『文件补齐』
- 若安装 bash-completion 软件,则在某些指令后面使用 [tab] 按键时,可以进行『选项/参数的补齐』功能
同时tab还可以提示指令,只需输入两次tab键。
命令别名设定功能 alias
有些指令比较常用,但他有比较得长,这就比较麻烦,bash提供了一个命令别名设定功能。
例如:(需要注意的是要有单引号)
alias lm='ls -al'
工作控制、前景背景控制 job control, foreground, background
例如我们可以用ctrl+c来终止运行,其他例子在后面会提及
程序化脚本 shell scripts
在 Linux 底下的 shell scripts则发挥更为强大的功能,可以将你平时管理系统常需要下达的连续指令写成一个文件, 该文件并且可以透过对谈交互式的方式来进行主机的侦测工作。
同样的在后面会详细介绍。
通配符 Wildcard
例如再/bin下寻找sh结尾的文件,则可:
一些便于编辑的方法
换行输入
如果指令串太长的话,可用 \ 来进行换行。
cp /var/spool/mail/root /etc/crontab \
> /etc/fstab /root
需要注意的是输入\ 后面接的是回车,因为 \ 只会跳脱下一个字符。
快速删除
组合键 | 功能 |
---|---|
[ctrl]+u/[ctrl]+k | 分别是从光标处向前删除指令串 ([ctrl]+u) 及向后删除指令串 ([ctrl]+k)。 |
[ctrl]+a/[ctrl]+e | 分别是让光标移动到整个指令串的最前面 ([ctrl]+a) 或最后面 ([ctrl]+e)。 |
shell的变量功能
正如我们程序设计语言一样,shell也有变量功能,他们的作用也是一样的:加强指令(代码)的可读性以及方便性。
变量的取用和设置
变量的取用:echo
需要注意的是:在取用的时候需要在变量前面加一个$,否则就会出现下面情况
变量的设定以及取消
变量设定:
name=VBird
变量取消
unset myname
这里有几点注意的:
- 变量与变量内容以一个等号『=』来连结
- 等号两边不能直接接空格符
- 变量名称只能是英文字母与数字,但是开头字符不能是数字
- 变量内容若有空格符可使用双引号『"』或单引号『’』将变量内容结合起来
- 可用跳脱字符『 \ 』将特殊符号(如 [Enter], $, , 空格符, '等)变成一般字符
- 在一串指令的执行中,还需要藉由其他额外的指令所提供的信息时,可以使用反单引号『`指令`』或 『$(指令)』。特别注意,那个 ` 是键盘上方的数字键 1 左边那个按键,而不是单引号
- 若该变量为扩增变量内容时,则可用 “$变量名称” 或 ${变量} 累加内容,如下『PATH="$PATH":/home/bin』或『PATH=${PATH}:/home/bin』
- 若该变量需要在其他子程序执行,则需要以 export 来使变量变成环境变量:『export PATH』
这里的子程序指的是,在我目前这个 shell 的情况下,去启用另一个新的 shell ,新的那个shell 就是子程序,在一般的状态下,父程序的自定义变量是无法在子程序内使用的。但是透过export 将变量变成环境变量后,就能够在子程序底下应用了。
环境变量的功能
环境变量可以帮我们达到很多功能~包括家目录的变换啊、提示字符的显示啊、执行文件搜寻的路径。
env和export
env是environment的缩写。
简单介绍一下部分变量的功能:
- HOME:用户的家目录
- SHELL:目前这个环境使用的 SHELL 是哪支程序,Linux 预设使用 /bin/bash
- HISTSIZE:目前shell可以记录的笔数
- MAIL:当我们使用 mail 这个指令在收信时,系统会去读取的邮件信箱文件
- PATH:执行文件搜寻的路径,由于文件的搜寻是依序由 PATH 的变量内的目录来查询,所以,目录的顺序也是重要
- LANG:语系数据(这个很重要,后续会详细介绍)
- RANDOM:随机随机数,使用echo $RANDOM系统则会随机出一个介于0~32767的数值
set
再终端输入set后,发现弹出了很多的信息,其中包括环境变量、用户自定义变量和一些与bash操作接口有关的变量。
下面简单介绍一下几个设定的变量
变量 | 作用 |
---|---|
PS1 | 命令提示字符,就是每次输入命令前,前面的提示信息,可以用man bash来进行查阅 |
$ | 当前shell的线程代号,也就是process ID,PID |
? | 记录上一条指令的传回值,执行某些指令时,这些指令都会有一个传回值,一般返回0说明成功执行该指令,如果不为0也方便我们找到问题所在 |
OSTYPE, HOSTTYPE, MACHTYPE | 主机硬件和核心的等级,由于不同等级的CPU 指令集不太相同,因此你的软件可能会针对某些 CPU 进行优化,以求取较佳的软件性能。所以软件就有 i386, i686 及 x86_64 之分 |
export
由上面可知由环境变量和自定义变量,这两者的区别主要是是否能再子程序中调用,子程序仅会继承父程序的环境变量, 子程序不会继承父程序的自定义变量。export可以将自定义变量转换为环境变量。
export 变量名
如果后面没加变量名,那么就会列出所有的环境变量。
变量键盘读取、数组与宣告
read
可以用来读取来自键盘输入的变量
read [-pt] variable
选项 | 作用 |
---|---|
-p | 后面可以接提示字符! |
-t | 后面可以接等待的『秒数』,当设定秒数之内没有输入,则自动退出 |
declare/typeset
两者是相同的功能,都是用来宣告变量的类型。
declare [-aixr] variable
选项 | 作用 |
---|---|
-a | 将后面名为 variable 的变量定义成为数组 (array) 类型 |
-i | 将后面名为 variable 的变量定义成为整数数字 (integer) 类型 |
-x | 用法与 export 一样,就是将后面的 variable 变成环境变量; |
-r | 将变量设定成为 readonly 类型,该变量不可被更改内容,也不能 unset |
整数变量类型
变量默认的类型是字符串类型,所以会有下面现象:
我们需要将变量设置为整数类型:
但需要注意的,如果一不小心将变量设置为仅读类型,通常得要注销再登入才能复原该变量的类型了
数组变量类型
数组的设定方式如下:
var[index]=content
文件系统及程序的限制关系
bash 是可以『限制用户的某些系统资源』的,包括可以开启的文件数量, 可以使用的 CPU 时间,可以使用的内存总量等等,这么做是为了防止用户数量过多导致占用了太多的资源。
ulimit [-SHacdfltu] [配额]
选项 | 参数 |
---|---|
-H | hard limit ,严格的设定,必定不能超过这个设定的数值; |
-S | soft limit ,警告的设定,可以超过这个设定值,但是若超过则有警告讯息。在设定上,通常 soft 会比 hard 小,举例来说,soft 可设定为 80 而 hard设定为 100,那么你可以使用到 90 (因为没有超过 100),但介于 80~100 之间时,系统会有警告讯息通知你! |
-a | 后面不接任何选项与参数,可列出所有的限制额度; |
-c | 限制每个核心文件的最大容量。 |
-f | 此 shell 可以建立的最大文件容量(一般可能设定为 2GB)单位为 Kbytes |
-d | 程序可使用的最大**断裂内存(segment)**容量; |
-l | 可用于锁定 (lock) 的内存量 |
-t | 可使用的最大 CPU 时间 (单位为秒) |
-u | 单一用户可以使用的最大程序(process)数量。 |
下面来解释一下上面几个概念:
- 核心文件:其实就是内存的映像,当程序崩溃时,存储内存的相应信息,主用用于对程序进行调试。当程序崩溃时便会产生core文件,其实准确的应该说是core dump 文件,默认生成位置与可执行程序位于同一目录下,文件名为core.*** ,其中***是某一数字
- 断裂内存:访问的内存超出了系统给这个程序(shell)所设定的内存空间,例如访问了不存在的内存地址、访问了系统保护的内存地址、访问了只读的内存地址等等情况
下面列出的是所有限制的额度:
需要注意的是:
- 想要复原 ulimit 的设定最简单的方法就是注销再登入,否则就是得要重新以 ulimit 设定才行不过
- 一般身份使用者如果以 ulimit 设定了 -f 的文件大小, 那么他只能继续减小文件容量,不能增加文件容量
变量内容的删除、取代与替换
前面提到可以用unset指令对变量进行变量的取消,当然我们也可以对变量的内容进行删除取代替换等操作
变量的删除
下面列出几种变量的删除方式:
指令 | 作用 |
---|---|
${变量#关键词} | 若变量内容从头开始的数据符合『关键词』,则将符合的最短数据删除 |
${变量##关键词} | 若变量内容从头开始的数据符合『关键词』,则将符合的最长数据删除 |
${变量%关键词} | 若变量内容从尾向前的数据符合『关键词』,则将符合的最短数据删除 |
${变量%%关键词} | 若变量内容从尾向前的数据符合『关键词』,则将符合的最长数据删除 |
变量的替换
指令 | 作用 |
---|---|
${变量/旧字符串/新字符串} | 若变量内容符合『旧字符串』则『第一个旧字符串会被新字符串取代』 |
${变量//旧字符串/新字符串} | 若变量内容符合『旧字符串』则『全部的旧字符串会被新字符串取代』 |
变量的测试
附上一张表格:
变量设定方式 | str没有设定 | str为空字符串 | str已设定非为空字符串 |
---|---|---|---|
var=${str-expr} | var=expr | var= | var=$str |
var=${str:-expr} | var=expr | var=expr | var=$str |
var=${str+expr} | var= | var=expr | var=expr |
var=${str:+expr} | var= | var= | var=expr |
var=${str=expr} | str=expr,var=expr | str 不变,var= | str 不变,var=$str |
var=${str:=expr} | str=expr,var=expr | str=expr,var=expr | |
var=${str?expr} | expr 输出至 stderr | var= | var=$str |
var=${str:?expr} | expr 输出至 stderr expr | 输出至 stderr | var=$str |
命令别名和历史命名
命令别名设定alias
主要有以下几个指令:
alias 别名='指令 选项...' #设置别名
alias #显示目前的命名别名
unalias 别名 #取消别名
那么命令别名和变量有什么区别?
命令别名是『新创一个新的指令, 你可以直接下达该指令』的,至于变量则需要使用类似『 echo 』指令才能够呼叫出变量的内容
历史命名history
前面给提到古bash有命令编修功能history,history指令可以用来查询输入过的指令
history [n]
history [-c]
history [-raw] histfiles
选项 | 作用 |
---|---|
n | 数字,意思是『要列出最近的 n 笔命令行表』的意思 |
-c | 将目前的 shell 中的所有 history 内容全部消除 |
-a | 将目前新增的 history 指令新增入 histfiles 中,若没有加 histfiles ,则预设写入 ~/.bash_history |
-r | 将 histfiles 的内容读到目前这个 shell 的 history 记忆中; |
-w | 将目前的 history 记忆内容写入 histfiles 中 |
需要注意的是
- 历史命令在我注销时,会将最近的 HISTFILESIZE 笔记录到我的纪录文件当中,当然你也可以对他进行强制写入
- ~/.bash_history 记录的笔数永远都是 HISTFILESIZE 那么多,旧的讯息会被主动的拿掉, 仅保留最新的
进而我们对输入history后得到的信息进行一些处理,例如:
- !number:执行第几条指令
- !command:由最近的指令向前搜寻『指令串开头为 command』的那个指令,并执行
- !!:就是执行上一个指令(相当于按↑按键后,按 Enter)
bash的操作环境
路径与指令顺序搜索
指令运作的顺序一般为以下几个步骤:
- 以相对/绝对路径执行指令,例如『 /bin/ls 』或『 ./ls 』;
- 由 alias 找到该指令来执行;
- 由 bash 内建的 (builtin) 指令来执行;
- 透过 $PATH 这个变量的顺序搜寻到的第一个指令来执行。
进站与欢迎信息
终端机接口 (tty1 ~ tty6) 登入的时候,会有几行提示的字符串,这些字符串被存储在**/etc/issue中**
下面介绍一下各个代码的意义:
代码 | 意义 |
---|---|
\d | 本地端时间的日期; |
\l | 显示第几个终端机接口; |
\m | 显示硬件的等级 (i386/i486/i586/i686…); |
\n | 显示主机的网络名称; |
\O | 显示 domain name; |
\r | 操作系统的版本 (相当于 uname -r) |
\t | 显示本地端时间的时间; |
\S | 操作系统的名称; |
\v | 操作系统的版本。 |
照着书上的进行修改,没有成功。通过搜索,发现进站信息还被存储在下面的文件中,对文件进行修改即可。
例如:
环境配置文件
因为配置文件的存在,所以我们在登录bash就规划好了操作环境。
需要注意的是,之前提到的变量别名在我们注销bash后便会失效,若想保留设定,那么就需要将别名写入配置文件内。
no-login shell和login shell
- login shell:取得 bash 时需要完整的登入流程的,就称为 login shell。举例来说,你要由 tty1 ~ tty6 登入,需要输入用户的账号与密码,此时取得的 bash 就称为『 login shell 』
- non-login shell:取得 bash 接口的方法不需要重复登入的举动,举例来说,(1)你以 X window 登入 Linux 后,再以 X 的图形化接口启动终端机,此时那个终端接口并没有需要再次的输入账号与密码,那个 bash 的环境就称为 non-login shell 了。(2)你在原本的 bash 环境下再次下达 bash 这个指令,同样的也没有输入账号密码, 那第二个 bash (子程序) 也是 non-login shell 。
这两种登录方式的不同,也将导致他们读取的配置文件数据不同,一般来说,login shell会读取下面两个文件:
- /etc/profile:这是系统整体的设定,你最好不要修改这个文件;
- ~/.bash_profile 或 ~/.bash_login 或 ~/.profile:属于使用者个人设定,你要改自己的数据,就写入这里!
login 读取流程
终端机
可以用stty查看所有的组合按键内容,一般有下以几种:
按键 | 作用 |
---|---|
Ctrl + C | 终止目前的命令 |
Ctrl + D | 输入结束 (EOF),例如邮件结束的时候; |
Ctrl + M | 就是 Enter 啦! |
Ctrl + S | 暂停屏幕的输出 |
Ctrl + Q | 恢复屏幕的输出 |
Ctrl + U | 在提示字符下,将整列命令删除 |
Ctrl + Z | 『暂停』目前的命令 |
数据流重导向
什么是数据流重导向?
简单来讲就是:将指令返回的内容输出不再输出到屏幕,输出到文件或者装置中去
standard output 与 standard error output
-
标准输出:读取 /etc/crontab 后,将该文件内容显示到屏幕上;简称stdout
-
标准错误输出:因为无法找到 /etc/vbirdsay,因此在屏幕上显示错误讯息;简称stderr
他们分别对应:
- 标准输出 (stdout):代码为 1 ,使用 > 或 >> ;
- 标准错误输出(stderr):代码为 2 ,使用 2> 或 2>> ;
怎么使用?在原先指令的基础上加上> directory即可。
那么>和>>又有什么区别呢?
代码 | 作用 |
---|---|
1> | 以覆盖的方法将『正确的数据』输出到指定的文件或装置上; |
1>> | 以累加的方法将『正确的数据』输出到指定的文件或装置上; |
2> | 以覆盖的方法将『错误的数据』输出到指定的文件或装置上; |
2>> | 以累加的方法将『错误的数据』输出到指定的文件或装置上; |
如果要将正确与错误数据通通写入同一个文件去呢?
不可以选择find /home -name .bashrc > list 2> list的方式,由于两股数据同时写入一个文件,又没有使用特殊的语法, 此时两股数据可能会交叉写入该文件内,造成次序的错乱。
下面两种方法均可:
find /home -name .bashrc > list 2>&1
find /home -name .bashrc &> list
standard input
以最简单的说法来说, 那就是将原本需要由键盘输入的数据,改由文件内容来取代的意思。
例如:
cat > catfile < ~/.bashrc
便可将~/.bashrc中的内容输入到catfile中去(cat > catfile可以用来建立一个文件)
这里需要注意的是:<需要按下 [ctrl]+d 来离开,而利用 << 右侧的控制字符,我们可以终止一次输入如下所示:
命令执行的判断依据
指令下达情况 | 说明 |
---|---|
cmd1 && cmd2 | 1. 若 cmd1 执行完毕且正确执行( ? = 0 ) , 则 开 始 执 行 c m d 2 。 2. 若 c m d 1 执 行 完 毕 且 为 错 误 ( ?=0),则开始执行 cmd2。2. 若 cmd1 执行完毕且为错误 ( ?=0),则开始执行cmd2。2.若cmd1执行完毕且为错误(?≠0),则 cmd2 不执行。 |
cmd1 || cmd2 | 1. 若 cmd1 执行完毕且正确执行( ? = 0 ) , 则 c m d 2 不 执 行 。 2. 若 c m d 1 执 行 完 毕 且 为 错 误 ( ?=0),则 cmd2 不执行。2. 若 cmd1 执行完毕且为错误 ( ?=0),则cmd2不执行。2.若cmd1执行完毕且为错误(?≠0),则开始执行 cmd2。 |
管线命令pipe
管线命令 |
这个管线命令『 | 』仅能处理经由前面一个指令传来的正确信息,也就是 standard output 的信息,对于stdandard error 并没有直接处理的能力
例如:
ls -al /etc | less
即可用less处理ls的信息,这样可以用less的功能,便于我们阅览信息。
如果你硬要让 standard error 可以被管线命令所使用,那该如何处理?其实就是透过上一小节的数据流重导向即可! 让 2>&1 加入指令中~就可以让 2> 变成 1>
撷取命令 cut, grep
cut
cut通常用于取出一行讯息当中我们想要的部分。
cut -d'分隔字符' -f fields
cut -c 字符区间
注意不能只进行分割:
选项 | 作用 |
---|---|
-d | 后面接分隔字符。与 -f 一起使用; |
-f | 依据 -d 的分隔字符将一段讯息分区成为数段,用 -f 取出第几段的意思; |
-c | 以字符 (characters) 的单位取出固定字符区间; |
grep
grep 则是分析一行讯息, 若当中有我们所需要的信息,就将该行拿出来。
grep [-acinv] [--color=auto] '搜寻字符串' filename
选项 | 作用 |
---|---|
-a | 将 binary 文件以 text 文件的方式搜寻数据 |
-c | 计算找到 ‘搜寻字符串’ 的次数 |
-i | 忽略大小写的不同,所以大小写视为相同 |
-n | 顺便输出行号 |
-v | 反向选择,亦即显示出没有 ‘搜寻字符串’ 内容的那一行 |
–color=auto | 可以将找到的关键词部分加上颜色的显示 |
排序命令:sort, wc, uniq
sort
可以用来排序,不过排序的字符与语系的编码有关,因此一般用LANG=C让语系同一。
sort [-fbMnrtuk] [file or stdin]
选项 | 作用 |
---|---|
-f | 忽略大小写的差异,例如 A 与 a 视为编码相同; |
-b | 忽略最前面的空格符部分; |
-M | 以月份的名字来排序,例如 JAN, DEC 等等的排序方法; |
-n | 使用『纯数字』进行排序(默认是以文字型态来排序的); |
-r | 反向排序; |
-u | 就是 uniq ,相同的数据中,仅出现一行代表; |
-t | 分隔符,预设是用 [tab] 键来分隔; |
-k | 以那个区间 (field) 来进行排序的意思 |
uniq
排序完成后,如果想让重复的数据只显示一行,那么可以使用uniq
uniq [-ic]
选项 | 作用 |
---|---|
-i | 忽略大小写字符的不同; |
-c | 进行计数 |
wc
wc [-lwm]
选项 | 作用 |
---|---|
-l | 仅列出行; |
-w | 仅列出多少字(英文单字); |
-m | 多少字符; |
需要注意的是:输出的三个数字中,分别代表: 『行、字数、字符数』
双向重导向 tee
> 会将所有数据都存储到装置或者文件中去,否则无法利用这个数据流。如果需要打印信息到屏幕上该怎么操作?使用tee指令即可
tee [-a] file
-a :以累加 (append) 的方式,将数据加入 file 当中!
文字转换命令 tr, col, join, paste, expand
tr
用来删除一段讯息当中的文字,或者是进行文字讯息的替换.
tr [-ds] SET1
选项 | 作用 |
---|---|
-d | 删除讯息当中的 SET1 这个字符串; |
-s | 取代掉重复的字符! |
join
用于处理两个文件之间的数据, 而且,主要是在处理两个文件当中,有 “相同数据” 的那一行,将他加在一起
join [-ti12] file1 file2
选项 | 作用 |
---|---|
-t | join 默认以空格符分隔数据,并且比对『第一个字段』的数据,如果两个文件相同,则将两笔数据联成一行,且第一个字段放在第一个 |
-i | 忽略大小写的差异; |
-1 | 这个是数字的 1 ,代表『第一个文件要用那个字段来分析』的意思; |
-2 | 代表『第二个文件要用那个字段来分析』的意思。 |
需要注意的是:
-1和-2后面都需要接上数字,用来表示第几个字段,(因为join默认空格分割数据)
paste
用于将两行贴在一起,且中间以 [tab] 键隔开
paste [-d] file1 file2
选项 | 作用 |
---|---|
-d | 后面可以接分隔字符。预设是以 [tab] 来分隔的! |
- | 如果 file 部分写成 - ,表示来自 standard input 的资料的意思。 |
expand
用于将 [tab] 按键转成空格键
expand [-t] file
-t :后面可以接数字。一般来说,一个 tab 按键可以用 8 个空格键取代。我们也可以自行定义一个 [tab] 按键代表多少个字符
分区命令 split
Windows 操作系统下,文件的分区很麻烦,在Linux中只需要一行指令。
split [-bl] file PREFIX
选项 | 作用 |
---|---|
-b | 后面可接欲分区成的文件大小,可加单位,例如 b, k, m 等; |
-l | 以行数来进行分区。 |