本文非原创,而是《鸟哥的Linux私房菜》的读书笔记,学习内容来自:《鸟哥的Linux私房菜》,版权归鸟哥。
关于shell
- 常见shell
- Bourne SHell (sh)
- 在 Sun 里头默认的 C SHell
- 商业上常用的 K SHell
- TCSH
- …
- 关于shell
查看当前进程中使用的shellps | grep $$ | awk '{print $4}'
。
当前有哪些可以使用的shell?可以查看/etc/shells
。
登录时,系统会给我用哪个shell?看/etc/passwd
。
如何知道命令是来自于外部命令(指的是其他非 bash 所提供的命令) 或是内建在 bash 当中的呢?type [-tpa] name
shell变量
-
什么是变量?
变量就是以一组文字或符号等,来取代一些配置或者是一串保留的数据! -
如何显示变量?
使用echo
,变量在被取用时,前面必须要加上$
才行。举例说明:echo $PATH
或者echo ${PATH}
-
如何设置或者修改变量内容?
使用=
连接即可。举例:myName=wangzz
。
值得注意的是:- 等号(
=
)两边不能直接接空格,错误实例yourName = Kobe
,这与大多数人编程习惯不同,需要注意。 - 变量名称只能是英文字母与数字,且不能以数字开头。(经过尝试,下划线也可以),错误示例:
2B=xx
- 变量内容若有空格符可使用双引号
"
或单引号'
将变量内容结合起来,但要注意:- 双引号内的特殊字符如
$
等,可以保有原本的特性,如下所示:var="lang is $LANG"
则echo $var
可得lang is en_US
。 - 单引号内的特殊字符则仅为一般字符 (纯文本),如下所示:
var='lang is $LANG'
则echo $var
可得lang is $LANG
- 双引号内的特殊字符如
- 可用字符
\
将特殊符号(如 [Enter], $, , 空格符, '等)变成一般字符; - 在一串命令中,还需要使用由其他命令,可使用反单引号````命令
```或 ```$(命令)```,比如:```path=
pwd` ``` - 如果想追加变量内容,比如想给
name=Messi
变量增加内容,可以这么做:name="$name"IsMagic
,或者是name=${name}IsMagic
。 - 若该变量需要在其他子程序运行,则需要以 export 来使变量变成环境变量:
export PATH
。经尝试,子程序export并不能使变量变成环境变量而在父程序使用。 - 删除变量使用
unset
。 declare
作用-
语法:
declare [+/-][rxi][变量名称=设置值] 或 declare -f
-
声明变量并设置变量的属性([rix]即为变量的属性)
+/-
"-“可用来指定变量的属性,”+"则是取消变量所设的属性。但是+a
和+r
无效,无法删除数组和只读属性,可以使用unset
删除数组,但是unset
不能删除只读变量-a
设置变量为数组array-A
声明关联数组,可以使用字符串作为数组索引-f
如果后面没有参数的话会列出之前脚本定义的所有函数,如果有参数的话列出以参数命名的函数-F
不显示函数定义-i
设置变量为整数-l
大写字母变小写,这儿是L
的小写l
,意思是lowercase。不是大写I
哦。-r
将变量设置为只读,设置为只读后,只有注销再登录才能恢复变量原来类型。-t
设置跟踪属性,用于跟踪函数进行调试,对于变量没有特殊意义-u
变量值的大写字母变为大写-x
指定的变量会成为环境变量,可供shell以外的程序来使用。-p
显示变量定义的方式和值
-
用来显示shell函数。若不加上任何参数,则会显示全部的shell变量与函数(与执行
set
指令的效果相同)。
-
- 等号(
-
使用
set
观察所有变量 (含环境变量与自定义变量)- PS1:(提示字符的配置)
- 提示字符是什么?登录后每次敲命令时显示的这部分
[root@wangzz shelldemo]$
这个便是。为什么显示这样子,便是由PS1变量决定,当然你可以更改。 \d
:可显示出『星期 月 日』的日期格式,如:“Mon Feb 2”\H
:完整的主机名。举例来说,鸟哥的练习机为『www.vbird.tsai』\h
:仅取主机名在第一个小数点之前的名字,如鸟哥主机则为『www』后面省略\t
:显示时间,为 24 小时格式的『HH:MM:SS』\T
:显示时间,为 12 小时格式的『HH:MM:SS』\A
:显示时间,为 24 小时格式的『HH:MM』\@
:显示时间,为 12 小时格式的『am/pm』样式\u
:目前使用者的账号名称,如『root』;\v
:BASH 的版本信息,如鸟哥的测试主板本为 3.2.25(1),仅取『3.2』显示\w
:完整的工作目录名称,由根目录写起的目录名称。但家目录会以 ~ 取代;\W
:利用 basename 函数取得工作目录名称,所以仅会列出最后一个目录名。\#
:下达的第几个命令。\$
:提示字符,如果是 root 时,提示字符为 # ,否则就是 $ 啰~(没有故意卖萌,原话是鸟哥说的)
- 提示字符是什么?登录后每次敲命令时显示的这部分
- $:(关于本 shell 的 PID)
echo $$
:显示当前shell的PID
- ?:(关于上个运行命令的回传值)
- 是什么意思?当我们每运行一个命令后,这个命令都会返回一个运行结果的代码值。一般成功是0,失败是其他值。示例:
[root@wangzz shelldemo]$ wangzz
bash: wangzz: command not found
[root@wangzz shelldemo]$ echo $?
127
- 是什么意思?当我们每运行一个命令后,这个命令都会返回一个运行结果的代码值。一般成功是0,失败是其他值。示例:
- PS1:(提示字符的配置)
-
键盘读取变量
- 使用
read
来读取键盘输入的变量。- 语法
read [-pt] variable
-p
:后面可以接提示字符-t
:后面可以接等待的时间(秒)
- 语法
- 使用
-
declare 与 typeset
- 若不使用declare或者typeset,变量类型默认为字符串,无法进行数字计算等操作。
- bash中数字类型变量,只有整数,无浮点数等。
-
ulimit
- 作用:限制用户可以使用的某些资源,如:可以开启的文件数量,可以使用的CPU时间,可以使用的内存总量等。
ulimit [-SHacdfltu] [配额]
- 选项与参数:
-H
:hard limit ,严格的配置,必定不能超过这个配置的数值;-S
:soft limit ,警告的配置,可以超过这个配置值,但是若超过则有警告信息。
在配置上,通常 soft 会比 hard 小,举例来说,soft 可配置为 80 而 hard
配置为 100,那么你可以使用到 90 (因为没有超过 100),但介于 80~100 之间时,
系统会有警告信息通知你!-a
:后面不接任何选项与参数,可列出所有的限制额度;-c
:当某些程序发生错误时,系统可能会将该程序在内存中的信息写成文件(除错用),
这种文件就被称为核心文件(core file)。此为限制每个核心文件的最大容量。-f
:此 shell 可以创建的最大文件容量(一般可能配置为 2GB)单位为 Kbytes-d
:程序可使用的最大断裂内存(segment)容量;-l
:可用于锁定 (lock) 的内存量-t
:可使用的最大 CPU 时间 (单位为秒)-u
:单一用户可以使用的最大程序(process)数量。-n
:同时开启的文件数量- …
-
变量内容的删除、取代与替换(所有都只是显示,不改变变量内容,除了使用
=
)- 从匹配到的前往后删除
#
- 语法:
echo ${path#/*:}
,删除匹配的最短的那个。可以使用*
匹配所有。 #
:符合取代文字的『最短的』那一个;##
:符合取代文字的『最长的』那一个
- 语法:
- 从匹配到的最后一个往前删除
%
- 语法:
echo ${path%:*bin}
- 注意:和上面的写法除了#变成%外,其他不变。我开始写时候,匹配的字符也是从后往前写,结果删除不掉。
%
:符合取代文字的『最短的』那一个;%%
:符合取代文字的『最长的』那一个
- 语法:
- 替换
- 替换第一处:
echo {path/bin/BIN}
- 替换全部:
echo {path//bin/BIN}
- 替换第一处:
- 变量值判断后替换
new_var=${old_var-content}
:如果变量不存在用content替换,如果存在则使用原来值。username=${username:-root}
:如果变量不存在或者为空字符串,则替换。否则使用原来值。
- 变量不存在报错:
echo ${var?error}
+
与上面4的-
相反- 使用
=
可以实际地替换变量值。wangzz=${str=newStr}
- 从匹配到的前往后删除
Bash Shell 的操作环境
-
命令运行的顺序
- 以相对/绝对路径运行命令,例如『 /bin/ls 』或『 ./ls 』
- 由 alias 找到该命令来运行
- 由 bash 内建的 (builtin) 命令来运行;
- 透过 $PATH 这个变量的顺序搜寻到的第一个命令来运行
-
bash 的进站与欢迎信息: /etc/issue, /etc/motd
- issue 内的各代码意义
\d
本地端时间的日期;\l
显示第几个终端机接口;\m
显示硬件的等级 (i386/i486/i586/i686…);\n
显示主机的网络名称;\o
显示 domain name;\r
操作系统的版本 (相当于 uname -r)\t
显示本地端时间的时间;\s
操作系统的名称;\v
操作系统的版本。
- motd是 登陆后提供的一些信息
- issue 内的各代码意义
-
bash 的环境配置文件
-
login 与 non-login shell
- login shell:取得 bash 时需要完整的登陆流程的,就称为 login shell。
- non-login shell:取得 bash 接口的方法不需要重复登陆的举动。比如直接
bash
,回车。
-
login shell 会读取的两个配置文件:
- /etc/profile:系统整体的配置,不要乱修改;同时该文件也会读取其他的配置文件。
- PATH:会依据 UID 决定 PATH 变量要不要含有 sbin 的系统命令目录;
- MAIL:依据账号配置好使用者的 mailbox 到 /var/spool/mail/账号名;
- USER:根据用户的账号配置此一变量内容;
- HOSTNAME:依据主机的 hostname 命令决定此一变量内容;
- HISTSIZE:历史命令记录笔数。
- ~/.bash_profile 或 ~/.bash_login 或 ~/.profile:属于使用者的配置,你要改自己的数据,就写入这里! bash 的 login shell 配置只会读取上面三个文件的其中一个, 而读取的顺序则是依照上面的顺序。也就是说如果第一个文件存在,其他的不管存在不存在都不会读取。
- 查看.bash_profile可以发现,里面会判断家目录下的 ~/.bashrc 存在否,若存在则读入 ~/.bashrc 的配置。所以可以将自己的偏好设置放到~/.bashrc中。
- /etc/profile:系统整体的配置,不要乱修改;同时该文件也会读取其他的配置文件。
-
source :读入环境配置文件的命令
- source可以不用注销再登录,就可以将配置生效。
.
点也可以使配置立即生效。. ~/.bashrc
。
-
~/.bashrc (non-login shell 会读)
-
终端机的环境配置: stty, set
- eof : End of file 的意思,代表『结束输入』。
- erase : 向后删除字符,
- intr : 送出一个 interrupt (中断) 的讯号给目前正在 run 的程序;
- kill : 删除在目前命令列上的所有文字;
- quit : 送出一个 quit 的讯号给目前正在 run 的程序;
- start : 在某个程序停止后,重新启动他的 output
- stop : 停止目前屏幕的输出;
- susp : 送出一个 terminal stop 的讯号给正在 run 的程序。
-
bash 环境中的特殊符号
-
符号 | 内容 |
---|---|
# | 批注符号:这个最常被使用在 script 当中,视为说明!在后的数据均不运行 |
\ | 跳脱符号:将『特殊字符或通配符』还原成一般字符 |
| | 管线 (pipe):分隔两个管线命令的界定(后两节介绍) |
; | 连续命令下达分隔符:连续性命令的界定 (注意!与管线命令并不相同) |
~ | 用户的家目录 |
$ | 取用变量前导符:亦即是变量之前需要加的变量取代值 |
& | 工作控制 (job control):将命令变成背景下工作 |
! | 逻辑运算意义上的『非』 not 的意思! |
/ | 目录符号:路径分隔的符号 |
>,>> | 数据流重导向:输出导向,分别是『取代』与『累加』 |
<,<< | 数据流重导向:输入导向 (这两个留待下节介绍) |
‘’ | 单引号,不具有变量置换的功能 |
“” | 具有变量置换的功能! |
`` | 两个『 ` 』中间为可以先运行的命令,亦可使用 $( ) |
() | 在中间为子 shell 的起始与结束 |
{} | 在中间为命令区块的组合! |
数据流重导向
- 什么是数据流重导向?
- 通常我们运行一个命令,这个命令可能回从文件读取数据,经过处理后,再将数据输出到屏幕上。数据流重导向就是将某个命令运行后应该要出现在屏幕上的数据,给他传输到其他的地方,例如文件或者是装置 (例如打印机之类的)!
- 标准输出与标准错误输出:标准输出是命令运行后输出的正确信息,显然另一个是输出的错误信息。
- 有关代码与字符
- 标准输入 (stdin) :代码为 0 ,使用 < 或 << ;
- 标准输出 (stdout):代码为 1 ,使用 > 或 >> ;
>
会将内容覆盖>>
不会覆盖,会追加内容
- 标准错误输出(stderr):代码为 2 ,使用 2> 或 2>> ;
- 追加或者覆盖情况与标准输出一样
/dev/null
用法(控设备,鸟哥称为垃圾桶黑洞装置)- 特殊写法:标准输出与标准错误输出写入同一文件:
2>&1
或者&>
find /home -name .bashrc > list 2>&1
find /home -name .bashrc &> list
- 标准输入
<
或<<
- 是什么?
将原本需要由键盘输入的数据,改由文件内容来取代
- 使用cat来创建文件
cat > file_name
,之后输入文件内容,完成后Ctrl+d。 - 使用别的文件内容来替代键盘输入:
cat > filename < src_file
<<
又是做什么的额?表示输入的结束字符,可以替代Ctrl+d。cat > catfile << "eof"
- 是什么?
- 通常我们运行一个命令,这个命令可能回从文件读取数据,经过处理后,再将数据输出到屏幕上。数据流重导向就是将某个命令运行后应该要出现在屏幕上的数据,给他传输到其他的地方,例如文件或者是装置 (例如打印机之类的)!
- 命令运行的判断依据: ; , &&, ||
cmd ; cmd
(不考虑命令相关性的连续命令下达)就是说两个命令没有关联,只是依次执行两个命令而已。- 在命令与命令中间利用分号 (😉 来隔开,这样一来,分号前的命令运行完后就会立刻接着运行后面的命令了。
$? (命令回传值) 与 && 或 ||
前后运行的命令有相关性,如第二个命令运行是否运行正确来判断第二个命令是否要运行。每个命令运行完成会有个返回值,依据就是这个返回值。类似编程里面的短路概念。cmd1 && cmd2
- 若 cmd1 运行完毕且正确运行($?=0),则开始运行 cmd2。
- 若 cmd1 运行完毕且为错误 ($?≠0),则 cmd2 不运行。
cmd1 || cmd2
- 若 cmd1 运行完毕且正确运行($?=0),则 cmd2 不运行。
- 若 cmd1 运行完毕且为错误 ($?≠0),则开始运行 cmd2。
管线(管道)命令 (pipe)
-
例子:
ls -al|less
-
管线命令
|
仅能处理经由前面一个命令传来的正确信息,也就是 standard output 的信息,对于 stdandard error 并没有直接处理的能力。管道后面必须接一个可以接受标准输入的命令。如: less, more, head, tail- 管道命令仅会处理 standard output,对于 standard error output 会予以忽略
- 管道命令必须要能够接受来自前一个命令的数据成为 standard input 继续处理才行
-
截取命令
cut
,grep
。截取命令通常是针对一行来分析,并非全文。cut
-d
:后面接分隔字符。与 -f 一起使用;-f
:依据 -d 的分隔字符将一段信息分割成为数段,用 -f 取出第几段的意思;-c
:以字符 (characters) 的单位取出固定字符区间;- 例子:
last|cut -d ' ' -f 1
,export|head -n 1|cut -c 12-18
grep
解析一行文字,取得关键词,若该行有存在关键词,就会整行列出来!grep [-acinv] [--color=auto] '搜寻字符串' filename
-a
:将 binary 文件以 text 文件的方式搜寻数据-c
:计算找到 ‘搜寻字符串’ 的次数-i
:忽略大小写的不同,所以大小写视为相同-n
:顺便输出行号-v
:反向选择,亦即显示出没有 ‘搜寻字符串’ 内容的那一行!--color=auto
:可以将找到的关键词部分加上颜色的显示喔
- 例子:
grep -i 'manpath' /etc/man_db.conf
-
排序命令
sort, wc, uniq
-
sort [-fbMnrtuk] [file or stdin]
依据不同的数据型态来排序-f
:忽略大小写的差异,例如 A 与 a 视为编码相同;-b
:忽略最前面的空格符部分;-M
:以月份的名字来排序,例如 JAN, DEC 等等的排序方法;-n
:使用『纯数字』进行排序(默认是以文字型态来排序的);-r
:反向排序;-u
:就是 uniq ,相同的数据中,仅出现一行代表;-t
:分隔符,默认是用 [tab] 键来分隔;-k
:以那个区间 (field) 来进行排序的意思- 例子:
cat /etc/passwd | sort -t ':' -k 3
-
uniq [-ic]
将重复的行删除掉只显示一个-i
:忽略大小写字符的不同;-c
:进行计数
-
wc [-lwm]
-l
:仅列出行;-w
:仅列出多少字(英文单字);-m
:多少字符;
-
-
双向重导向:
tee [-a] file
- tee 会同时将数据流分送到文件去与屏幕 (screen);而输出到屏幕的,其实就是 stdout ,可以让下个命令继续处理喔!
-
字符转换命令:
tr, col, join, paste, expand
-
tr - translate or delete characters
替换或者删除字符串。tr [-ds] SET1 ...
-d
:删除信息当中的 SET1 这个字符串;-s
:取代掉重复的字符!
- 例子:
cat passwd |tr -d '\r' > ~/passwd.linux
-
col - filter reverse line feeds from input
- col [-xb]
-x
:将 tab 键转换成对等的空格键-b
:在文字内有反斜杠 (/) 时,仅保留反斜杠最后接的那个字符
- 例子```cat testChar.c|col -x|cat -A``
- col [-xb]
-
join - join lines of two files on a common field
join [-ti12] file1 file2
- -t :join 默认以空格符分隔数据,并且比对『第一个字段』的数据,
如果两个文件相同,则将两笔数据联成一行,且第一个字段放在第一个! -i
:忽略大小写的差异;-1
:这个是数字的 1 ,代表『第一个文件要用那个字段来分析』的意思;-2
:代表『第二个文件要用那个字段来分析』的意思。
- -t :join 默认以空格符分隔数据,并且比对『第一个字段』的数据,
-
paste - merge lines of files
- 将两行贴在一起,且中间以 [tab] 键隔开
paste [-d] file1 file2
-d
:后面可以接分隔字符。默认是以 [tab] 来分隔的!-
:如果 file 部分写成 - ,表示来自 standard input 的数据的意思
- 例子:
cat /etc/group|paste /etc/passwd /etc/shadow -|head -n 3
-
expand - convert tabs to spaces
- 将tab按键转成空格键(ps:这不就是
col -x
吗) expand [-t] file
-t
:后面可以接数字。一般来说,一个 tab 按键可以用 8 个空格键取代。
我们也可以自行定义一个 [tab] 按键代表多少个字符呢!
- 例子:
grep '^MANPATH' /etc/man_db.conf |head -n 3|expand -t 1|cat -A
,注意这儿添加多少空格并不是死值。
- 将tab按键转成空格键(ps:这不就是
-
-
分割命令: split
split - split a file into pieces
- 依据文件大小或者行数来分割文件。
split [-bl] file PREFIX
-b
:后面可接欲分割成的文件大小,可加单位,例如 b, k, m 等;-l
:以行数来进行分割。
- PREFIX :代表前导符的意思,可作为分割文件的前导文字。
- 例子:
ls -al / | split -l 10 - lsroot
,这里注意,如果你忽略了-
,也就是这样输入ls -al|split -l 10 lsroot.
,你会得到这个错误:split: cannot open ‘ls.’ for reading: No such file or directory
。因为这里没有文件,这里的 - 就会被当成 stdin 或 stdout。
-
参数替换xargs
xargs - build and execute command lines from standard input
xargs [-0epn] command
-0
:如果输入的 stdin 含有特殊字符,例如 `, , 空格键等等字符时,这个 -0 参数
可以将他还原成一般字符。这个参数可以用于特殊状态喔!-e
:这个是 EOF (end of file) 的意思。后面可以接一个字符串,当 xargs 分析到
这个字符串时,就会停止继续工作!-p
:在运行每个命令的 argument 时,都会询问使用者的意思;-n
:后面接次数,每次 command 命令运行时,要使用几个参数的意思。看范例三。- 当 xargs 后面没有接任何的命令时,默认是以 echo 来进行输出!
- 例子:
find /sbin -perm +7000 | xargs ls -l
,find ./ -name "*" |xargs -p grep -n "ab"
。
-
关于减号 - 的用途
- 上面提到
-
可以当成 stdin 或 stdout。某些命令需要用到文件名 (例如 tar) 来进行处理时,该 stdin 与 stdout 可以利用减号 “-” 来替代, 举例来说:[root@www ~]# tar -cvf - /home | tar -xvf -
- 上面提到
正则表达式(鸟哥称为正规表达式)与文件格式化处理
鸟哥这里用了很大的篇幅介绍正则表达式,这儿大多数编程语言学习时候都会进行学习,所以不做重点学习,大概预览一下。