Linux操作系统架构
查看你的Linux中安装的shell
cat /etc/shells
输出结果示例:
# /etc/shells: valid login shells
/bin/sh
/bin/dash
/bin/bash
/bin/rbash
查看你的Linux当前使用的shell
echo $SHELL
ps $$
ps -p $$
命令行快捷键
你可以使用以下组合键来编辑或回调命令:
- CTRL + L : 清空屏幕
- CTRL + W : 删除光标所在处的单词
- CTRL + U : 清除整行,也就是,删除所有命令行的单词
- 上箭头和下箭头 : 调用历史命令
- TAB : 自动补全文件名、目录名、命令名等
- CTRL + R : 从历史命令中查找
- CTRL + C : 取消正在执行的命令
- CTRL + T : 交换光标所在处的前两个字符
- ESC + T : 交换光标所在处前两个单词
- CTRL + H : 删除光标所在处的字符
获取Linux命令帮助
可以使用man或info或-h或--help选项获取Linux命令的信息。
man commandName
info commandName
commandName -h
commandName --help
whereis命令
whereis命令被用来定位命令的二进制、源文件、和帮助文档页的路径:
whereis command-name
whereis ls
输出示例:
ls: /bin/ls /usr/share/man/man1/ls.1.gz
whatis命令
whatis命令用来显示命令的简短描述。whatis命令搜索命令的帮助文档并显示帮助文档的描述:
whatis command-name
whatis date
whatis ifconfig
whatis ping
输出示例:
date (1) - print or set the system date and time
ifconfig (8) - configure a network interface
ping (8) - send ICMP ECHO_REQUEST to network hosts
type命令
type
命令可以用来判断命令类型
在shell提示符输入以下命令:
type -a ls
输出示例:
ls is aliased to `ls --color=auto'
ls is /bin/ls
对于外部命令:
type -p date # /bin/date
which命令
which命令显示当前环境的可执行文件的路径。它是通过搜索PATH的可执行文件搜索目录匹配命令名来实现的。
你也可以使用which
命令来显示(shell)命令的全路径:
which commandname
which bash # /bin/bash
Linux哲学 - KISS
- 只做一件事并且做好 - 编写程序使其只做一件事并且做的好。编写程序使其一起工作。编写程序使其处理文本流,因为这是普遍的接口
- 一切皆文件。易用和安全是因为:把硬件当作文件
- 小即是美
- 使用纯文本格式存储数据和配置 - 文本文件是通用的接口。容易创建、备份和移植到其他系统
- 使用shell脚本增强优势和可移植性。使用shell自动完成在各种各样的Unix/Linux系统中的普通任务
- 链接简单的程序使其完成复杂的任务。使用shell管道符和过滤符链接实用小程序能够一次性完成任务执行
- 可移植性优先于效率
- 保持简单、易懂(KISS,Keep It Simple Stupid)
KISS = Keep It Simple Stupid
可以抽象为:
1、 模块性原则:写简单的,通过干净的接口可被连接的部件。
2、 清楚原则:清楚要比小聪明好。
3、 合并原则:设计能被其它程序连接的程序。
4、 分离原则:从机制分离出策略,从实现分离出接口。
5、 简单原则:设计要简单;只有当你需要的时候,增加复杂性。
6、 节俭原则:只有当被证实是清晰,其它什么也不做的时候,才写大的程序。
7、 透明原则:为使检查和调试明显更容易而设计。
8、 健壮性原则:健壮性是透明和简单的追随者。
9、 表现原则:把知识整理成资料,于是程序逻辑能变得易理解和精力充沛的。
10、 最小意外原则:在接口设计中,总是做最小意外事情。
11、 沉默原则:当一个程序令人吃惊什么也不说的时候,他应该就是什么也不说。
12、 修补补救:当你必须失败的时候,尽可能快的吵闹地失败。
13、 经济原则:程序员的时间是宝贵的;优化机器,节约时间。
14、 产生原则:避免手工堆砌;当你可以的时候,编写可以写程序的程序。
15、 优化原则:在雕琢之前先有原型;在你优化它之前,先让他可以运行。
16、 差异原则:怀疑所有声称的“唯一真理“。
17、 可扩展原则:为将来做设计,因为它可能比你认为来的要快。
shell脚本的组成
- shell关键字,比如
if...else...
和do...while
- shell命令,比如
pwd
、test
、echo
、continue
、type
- Linux二进制命令,比如
w
、who
、free
等等 - 文本处理程序,比如
grep
、awk
、cut
- 函数 - 将常用操作通过函数写到一起。例如,/etc/init.d目录下的/etc/init.d/functions文件中包含大部分或者说所有系统shell脚本
- 控制流声明,比如
if...then...else
或者处理重复任务的shell循环
Bash和命令类型
Bash shell可以理解以下几种类型的命令:
- 别名,比如
ll
- 关键字,比如
if
- 函数(用户定义的函数比如
genpasswd
) - 内置命令,比如
pwd
- 文件,比如
/bin/date
如何调试shell脚本
你需要加上-x选项来运行shell脚本:
bash -x script-name
或者
bash -xv script-name
你也可以更改shebang行,以调试模式运行整个脚本:
#!/bin/bash -x
echo "Hello ${LOGNAME}"
echo "Today is $(date)"
echo "Users currently on the machine, and their processes:"
w
常用shell变量
以下变量是由shell设置的:
系统变量 | 意义 | 查看变量值 |
---|---|---|
BASH_VERSION | 保存了当前bash实例的版本号 | echo $BASH_VERSION |
HOSTNAME | 你的电脑名称 | echo $HOSTNAME |
CDPATH | 命令cd的查找路径 | $CDPATH |
HISTFILE | 保存命令历史的文件名称 | echo $HISTFILE |
HISTFILESIZE | 命令历史文件的最大行数 | echo $HISTFILESIZE |
HISTSIZE | 命令历史保存的最大命令数。默认值是500 | echo $HISTSIZE |
HOME | 当前用户的家目录 | echo $HOME |
IFS | 内域分割符,使用read内置命令将行分割成单词。默认值是 |
echo $IFS |
LANG | 显示当前系统字符集 | echo $LANG |
PATH | 命令查找路径。它是一个冒号分隔的路径列表,shell从中查找命令 | echo $PATH |
PS1 | 你的命令提示符设置 | echo $PS1 |
TMOUT | 读取内置命令的默认过期时间。 | echo $TMOUT |
TERM | 你所登录的终端类型 | echo $TERM export TERM=vt100 |
SHELL | 设置登录shell的路径 | echo $SHELL |
DISPLAY | 设置登录图形界面的显示位置 | echo $DISPLAY export DISPLAY=:0.1 |
EDITOR | 设置默认文本编辑器的名称 | export EDITOR=/usr/bin/vim |
shell中的符号
引用
有三种形式的引用:
引用类型 | 名称 | 意义 | 示例(在shell提示符下输入) |
---|---|---|---|
" | 双引号 | 双引号("引号")保护所有在双引号内的东西,除了$、'、",和\。当你只想 解析变量和命令替代 时使用双引号。 * 变量 - 解析 * 通配符 - 不解析 * 命令替代 - 解析 |
双引号允许输出变量 $SHELL 的值,禁用了通配符的意义,并且允许命令替代。 echo "$SHELL" echo "/etc/*.conf" echo "Today is $(date)" |
' | 单引号 | 单引号('引号')保护所有在单引号内的东西。它被用来 禁用所有特殊意义 的字符。 * 变量 - 不解析 * 通配符 - 不解析 * 命令替代 - 不解析 |
单引号阻止显示 $SHELL 的值,禁用了通配符 /etc/*.conf 的意义,和命令替代($date )。 echo '$SHELL' echo '/etc/\**.conf' echo 'Today is \${date)' |
\ | 反斜线 | 使用反斜线来禁用特殊字符的意义,或者在文本中直接显示特殊字符而不对其进行解析,比如引号 | 你可以在美元符号前使用\来告诉shell使$没有特殊意义。禁用 $PATH 中$符号的意义(也就是不显示$PATH变量的值):echo "Path is \$PATH" echo "Path is $PATH" |
反斜线\
你可以使用反斜线(\)在一行的结尾作为最后一个字符来使命令可以在下一行继续。
反斜线(\)可以改变'和"的特殊意义,也就是说,它会转义或取消在它后面的字符的特殊意义。以下命令会将文件名显示在双引号中:
FILE="/etc/resolv.conf"
echo "File is \"$FILE\" "
输出示例:
File is "/etc/resolv.conf"
以下shell会移除美元符号($)的特殊意义:
FILE="/etc/resolv.conf"
echo "File is \$FILE "
输出示例:
File is $FILE
双引号""
用于输出变量
echo "$HOME"
大括号{}
封装变量名
echo "${HOME}"
printf "%s\n" ${HOME}
- 大括号({..})扩展用于创建模式,它的语法是:
{ pattern1, pattern2, patternN }
text{ pattern1, pattern2, patternN }
text1{ pattern1, pattern2, patternN }text2
command something/{ pattern1, pattern2, patternN }
- 它可以节省敲命令的时间。
- 可以生成任意字符串。
创建一个字符串模式:
echo I like {tom,jerry}
输出示例:
I like tom jerry
新建了一个字符串,然而它也可以用来创建唯一的文件名:
echo file{1,2,3}.txt
输出示例:
file1.txt file2.txt file3.txt
或者
echo file{1..5}.txt
输出示例:
file1.txt file2.txt file3.txt file4.txt file5.txt
生成文件名不需要其存在。你也可以运行在括号内的每一个模式的命令。通常,你也可以按以下方式列出三个文件:
ls -l /etc/resolv.conf /etc/hosts /etc/passwd
但是,通过大括号:
ls /etc/{resolv.conf,hosts,passwd}
输出示例:
/etc/hosts /etc/passwd /etc/resolv.conf
要删除名为:hello.sh、hello.py、hello.pl、和hello.c的文件,输入:
rm -v hello.{sh,py,pl,c}
另一个示例:
D=/webroot
mkdir -p $D/{dev,etc,bin,sbin,var,tmp}
小括号()
封装Linux命令
NOW=$(date)
echo $NOW
两个小括号进行数学运算:
echo $(( 5 + 5 ))
中括号[]
相当于test命令
if [ -f /etc/hosts ]
then
echo "/etc/hosts文件存在"
else
echo "/etc/hosts文件不存在"
fi
通配符?*[]{}
- Bash支持以下三种简单的通配符:
- * - 匹配任意字符,包括null字符
- ? - 匹配单个(一个)字符
- [...] - 匹配中括号中的任意一个字符
显示所有/etc目录下的所有配置(.conf)文件,输入:
ls /etc/*.conf
显示所有C项目头文件,输入:
ls *.h
显示所有C项目的.c文件,输入:
ls *.c
你可以结合通配符和大括号:
ls *.{c,h}
输出示例:
f.c fo1.c fo1.h fo2.c fo2.h fo3.c fo3.h fo4.c fo4.h fo5.c fo5.h t.c
列出所有png文件(image1.png, image2.png...image7.png, imageX.png),输入:
ls image?.png
列出所有以a或b开头的配置文件,输入:
ls /etc/[ab]*.conf
波浪线~
当前用户家目录
ls ~
&&和||以及!
- 逻辑与&& - 只有当第一个命令执行成功时才会执行第二个命令。
- 逻辑或|| - 只有当第一个命令执行不成功时才会执行第二个命令。
test 5 -gt 2 && echo "Yes" || echo "No"
export创建全局变量
在终端中依次输入以下命令:
myname=meimei
echo $myname
bash
echo $myname
你会发现什么?你会发现第一个echo输出了meimei,第二个echo输出结果为空。为什么输入命令bash后定义的变量myname的值就为空了呢?答案是因为bash命令新创建一个bash的进程,所以之前一个bash进程的变量名在新进程中是没有被定义的。
如果要想使定义的变量在新创建的bash进程中也能够使用,可以使用export命令。
在终端中输入以下命令:
export myname=meimei
echo $myname
bash
echo $myname
这时两个echo都能输出变量myname的值meimei。
使用export -p命令可以查看变量名列表。
export -p
使用export设置PATH环境变量
vim打开~/.bashrc,在最后添加:
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
或者,在原有PATH的基础上追加:
export PATH=$PATH:/usr/games:/usr/local/games
使bash立即生效:
bash ~/.bashrc
显示当前的环境变量:
echo $PATH
read命令语法
你可以通过read命令来从键盘读取输入,并将读取到的输入值赋值给一个用户定义的shell。
read -P "Prompt" variable1 variable2 variableN
其中:
- -p "Prompt" :不开启新行显示终端提示符给用户。
- variable1 :第一个输入(单词)赋值给variable1。
- variable2 :第二个输入(单词)赋值给variable2。
选项:
- -p "Prompt" :不开启新行显示终端提示符给用户。
- -s : 密码形式读取
- -t : 读取超时时间
if语句
单if
if [条件]
then
命令1
命令2
....
..
fi
嵌套if
if 条件
then
if 条件
then
.....
..
执行这里
else
....
..
执行这里
fi
else
...
.....
执行这里
fi
多层if
if 条件
then
条件为真
执行所有elif声明之前的命令
elif 条件1
then
条件为真
执行所有elif声明之前的命令
elif 条件2
then
条件2为真
执行所有elif声明之前的命令
elif 条件N
then
条件N为真
执行所有elif声明之前的命令
else
以上条件都不为真
执行所有fi之前的命令
fi
数值比较
test命令可以使用以下运算符执行各种各样的数值比较:
运算符 | 语法 | 说明 | 示例 |
---|---|---|---|
eq | 整数1 -eq 整数2 | 整数1等于整数2 | |
ge | 整数1 -ge 整数2 | 整数1大于或等于整数2 | |
gt | 整数1 -gt 整数2 | 整数1大于整数2 | |
le | 整数1 -le 整数2 | 整数1小于或等于整数2 | |
lt | 整数1 -lt 整数2 | 整数1小于整数2 | |
ne | 整数1 -ne 整数2 | 整数1不等于整数2 |
字符串比较
字符串相等
使用以下语法:
字符串1 = 字符串2
字符串长度为0
使用以下语法(这对检查变量是否为空很有用):
-z 字符串
文件属性比较
-a:如果文件存在则为true。
-d:文件存在并且是一个文件夹则为true。
-e:如果文件存在则为true。
-f:如果文件存在且是一个普通文件则为true。
-h:文件存在并且为一个符号链接则为true。
-r:文件存在并且可读则为true。
-s:文件存在并且文件大小大于0则为true。
-w:文件存在并且可写则为true。
-x:文件存在并且可执行则为true。
获取命令行参数
获取:$0、$1、$2......$n,$0为脚本名或命令名,$1往后为参数。
特殊参数
- 所有命令行参数或都可以通过$1,$2,$3,...,$9获取
- $*保存所有命令行参数
- $#保存位置参数的个数
- $-保存shell提供的标示
- $?保存上一个执行命令的返回值
- $$保存shell(当前shell)的进程号
- $!保存上一个后台命令的进程号
- $@保存所有命令行参数
$@和$*
$@ 扩展为"$1" "$2" "$3" ... "$n"
$* 扩展为"$1y$2y$3y...$n",其中y是$IFS(内域分隔符)的值,也就是说,"$*"是一个长字符串,而$IFS是一个分隔符或标记分隔符
示例:$@和$*的区别
创建一个名为pizza.sh的shell脚本:
#!/bin/bash
IFS=","
echo "* 使用\$@ 显示所有pizza的名称"
echo "$@"
echo
echo "* 使用\$*显示所有pizza的名称"
echo "$*"
保存并关闭文件。运行如下:
chmod +x pizza.sh
./pizza.sh Margherita Tomato Panner Gourmet
输出示例:
* 使用$@ 显示所有pizza的名称
Margherita Tomato Panner Gourmet
* 使用$*显示所有pizza的名称
Margherita,Tomato,Panner,Gourmet