此系列还有其余两篇,想完整掌握Linux的同学们可以一并阅读
Linux主要开发工具之gcc、gdb与make-CSDN博客Linux基础知识详解与命令大全(超详细)-CSDN博客
1.文本编辑
1.1 vi的工作方式
1.1.1 命令方式
当我们输入命令vi,进入 vi编辑器时,就处于vi的命令方式
通过输入vi的插入命令( i )、附加命令( a )、打开命令(o )、等可以从命令方式进入到插入方式。
由插入方式回到命令方式的办法是按下<Esc>键
注意:
命令方式可与插入方式及ex转义方式切换, 但插入方式与ex转义方式之间不可互相!
进入vi编辑器
1.1.2 输入方式
通过输入vi的插入命令( i )、附加命令( a )、打开命令(o)、替换命令( s )、修改命令( c )或取代命令( r )可以从命令方式进入到输入方式
由输入方式回到命令方式的办法是按下<Esc>键(通常在键盘的左上角)
1.1.3 ex转义方式
vi和ex编辑器功能是相同的,二者主要区别是用户界面。
- 在vi 中,命令通常是单个字母,例如a , x , R等。
- 在ex中,命令是以<Enter>键结束的正文行
- 为了使用ex转义方式,可输入一个冒号(:)
例如:
: 1 、 w、q、! <Enter>
1.2 进入和退出vi
1.2.1 进入vi
在系统提示符($ )下输入命令vi和想要编辑(建立)的文件名,便可进入vi。
例如:
$vi example.c
1.2.2 退出vi
- :wq 把编辑缓冲区的内容写到你编辑的文件中,退出编 辑器,回到 shell下。 (其操作过程是,先键入冒号“:”,再键入命令wq。以下命令操作相同。)
- :q! 强行退出vi。感叹号(! )告诉vi,无条件退出,丢弃缓冲区内容。
1.3 文本输入
1.3.1 插入命令(insert)
在 i 命令之后输入的内容都插在光标位置之前,光标后的文本相应向右移动。如按下Enter键,就插入新的一行或者换行。
输入 i 命令后在当前行(即光标所在行)的行首插入新增文本,行首是该行的第一个非空白字符。当输入i命令时,光标就移到行首。
下面这些命令要退出i命令(esc后可执行) ,自行尝试
1.3.2 附加命令
a 在光标之后插入,光标可在一行的任何位置。
A 在光标所在行的行尾添加文本。
1.3.3 打开命令
o 在光标所在行的下面插入一行。
O 在光标所在行的上面插入一行。
1.4 文本修改
1.4.1 文本删除
x 删除光标所在的字符
X 删除光标前面的那个字符
删除文本对象的命令(键):
dd 删除光标所在的整行
D 从光标位置开始删除到行尾
d<光标移动命令> 从光标位置开始删到由光标移动限定的文本对象的末尾
1.4.2 复原命令
u 如果插入后用u命令,就删除刚插入的正文;如果删除后用它,就相当于又插入刚删除的正文。
U 把当前行恢复成它被编辑之前的状态,不管你把光标移到该行后对它编辑了多少次。
1.4.3 重复命令
. 重复实现刚才的插入命令或删除命令。
1.4.4 取代命令
1.4.5 替换命令
1.5 编辑文件
编辑已存文件的最常用方式是:
$ vi 文件名
从某一指定行进入vi。其格式是:
$ vi +行号 文件名
从某一指定词进入vi。其格式是:
$ vi +/词 文件名
编辑多个文件
可以同时调入多个文件,依次对它们进行编辑。其命令格式是:
$ vi 文件1 文件2…
当完成对第一个文件的编辑及存盘(用:w命令)后,输入命令:n就进入第二个文件。
1.6 字符串检索
1.7 ex命令
进入ex 命令的方法是在命令方式下输入冒号(:),则在状态行上出现冒号提示符,随后就可输入ex 命令。
1.7.1 命令定位
: 20 <Enter> 光标移到第20行的行首。
: /this 按回车键
1.7.2 常用ex命令
w命令:
w(写)命令可把编辑缓冲区中全部或者部分内容写到当前文件或者另外某个文件中。它有以下几种常用形式 :
- w文件名——它把所做的修改写回到指定的文件,并显示所写的行数和字符数
- w>>文件名——它把缓冲区内容附加到现有文件的末尾,先前文件内容并不被破坏
- w! 文件名——它可跳过通常写命令对文件的检查,将缓冲区内容写到系统允许的任何文件上
- w !命令——它将指定的各行写入指定命令中
q命令:
q(退出)命令可从vi 中退出来。它有下述五种使用方式:
- q——它的功能是退出vi
- q!——它的功能是立即从vi 中退出,不保留所做的修改,也不显示任何提示信息
- wq文件名——它的功能等价于执行w命令后又执行q命令
- wq !文件名——它的功能是忽略执行w命令之前所做的检查
- x文件名——如果该文件做过修改,并且尚未写出去,那么这个命令就把缓冲区内容写出去,然后退出vi;否则,只是退出vi。
2 shell程序设计
2.1 shell概述
2.1.1 shell特点和主要版本
作为命令解释程序
一种高级程序设计语言,它有变量,关键字,有各种控制语句,如if、case、while、for等语句,支持函数模块,有自己的语法结构
shell特点:
☆组合新命令 ☆提供了文件名扩展字符
☆直接使用shell的内置命令 ☆灵活地使用数据流
☆结构化的程序模块 ☆在后台执行命令
☆可配置的环境 ☆高级的命令语言
shell种类:
(1) Bourne shell(简称sh)
(2) C shell(简称csh)
(3) Korn shell(简称ksh)
(4) Bourne Again shell(即bash)
2.1.2 shell程序实例
2.1.3 shell脚本的建立和执行
1.shell脚本的建立
2.执行shell脚本的方式
执行shell脚本的方式基本上有三种:
(1)输入定向到shell脚本
$ bash < 脚本名
(2)以脚本名作为参数
其一般形式是: $ bash 脚本名 [参数]
(3)将shell脚本的权限设置为可执行,然后在提示符下直接执行它。
# chmod a+x ex2
# PATH=$PATH:. (PATH=$PATH:/root/chapter4)
# ex2
注意:此时该脚本所在的目录应被包含在命令搜索路径中,即包含在环境变量PATH中。若不设置环境变量,则可以使用./等形式来指定脚本所在目录。
2.2 命令历史
2.2.1 显示历史命令
语法格式是:history [option] [arg…]
2.2.2 配置历史命令环境
- 在默认方式下,bash使用用户主目录下面的文件“.bash_history”来保存命令历史
- 改变存放历史命令的文件 :$ HISTFILE="/home/mengqc/.myhistory"
- 重新设定能够保留的命令个数 :$ HISTSIZE=60
2.3 名称补全
可以输入目录名或文件名的开头部分,然后按Tab键,Linux根据输入的字母查找以这些字母开头的目录或文件,并自动补全剩余的部分。
2.4 shell特殊字符
2.4.1 通配符
1.一般通配符
(1) *(星号),它匹配任意字符的0次或多次出现
(2) ?(问号),它匹配任意一个字符
(3) [ ](一对方括号),其中有一个字符组。其作用是匹配该字符组所限定的任何一个字符
(4) !(惊叹号),如果它紧跟在一对方括号的左方括号([)之后,则表示不在一对方括号中所列出的字符
2.4.2 引号
1.双引号
由双引号括起来的字符(除$、倒引号(`)和反斜线(\)外)均作为普通字符对待。
2.单引号
由单引号括起来的字符都作为普通字符出现。
3.倒引号
倒引号括起来的字符串被shell解释为命令行,在执行时,shell会先执行该命令行,并以它的标准输出结果取代整个倒引号部分。倒引号还可以嵌套使用。但应注意,嵌套使用时内层的倒引号必须用反斜线(\)将其转义。
2.4.3 输入/出重定向符
执行shell时自动打开三个标准文件,即标准输入文件(stdin),标准输出文件(stdout)和标准出错输出文件(stderr)。
1.输入重定向符
一般形式是:命令 < 文件名 如:$ score < file1
2.输出重定向符
一般形式是:命令 > 文件名 如:$ who > abc
输入和输出重新定向可以连在一起使用。例如: $ wc -l < infile > outfile
2.4.4 注释、管道线和后台命令
1.注释
#!/bin/bash
# If no arguments, then listing the current directory.
# Otherwise, listing each subdirectory.
2.管道线
ls -l $HOME | wc –l
ls | grep m?.c | wc –l
3.后台命令
$ gcc m1.c&
2.4.5 命令执行操作符
1.顺序执行
在执行时,以分号隔开的各条命令从左到右依次执行
例如:pwd ; who | wc -l ; cd /usr/bin
2.逻辑与
格式:命令1 && 命令2
功能:先执行命令1,如果执行成功,才执行命令2;
否则,若命令1执行不成功,则不执行命令2。
3.逻辑或
格式:命令1 || 命令2
功能:先执行命令1,如果执行不成功,则执行命令2;
否则,若命令1执行成功,则不执行命令2。
2.4.6 成组命令
1.{ }形式
以花括号括起来的全部命令可视为语法上的一条命令,出现在管道符的一边。
{ echo “User Report for ` date ` . ”; who ; } | pr
使用花括号时在格式上应注意:左括号 “{ ”后面应有一个空格;右括号“}”之前应有一个分号( ;)
2.( )形式
(echo "Current directory is ` pwd ` . "
cd /home/mengqc ; ls -l ;
cp m1 em1 && rm m1
cat em1) | pr
二者存在重要区别:
用花括号括起来的成组命令只是在本shell内执行命令表,不产生新的进程;而用圆括号括起来的成组命令是在新的子shell内执行,要建立新的子进程。
2.5 shell变量
2.5.1 用户定义的变量
1.变量名是以字母或下线符打头的字母、数字和下线符序列,并且大小写字母意义不同。
2.定义变量并赋值的一般形式是:
变量名=字符串
3.引用变量值:在变量名前面加上一个符号“$”
names="Zhangsan Lisi Wangwu"
echo $names
$ dir=/usr/meng
$ cat ${dir}qc/m1.c
4.命令替换
`命令表`
$(命令表)
如:$ dir=$(pwd)
$ echo $(pwd ; cd /home/mengqc ; ls -d)
2.5.2 数组
declare -a 数组名
${数组名[下标]}
数组名=(值1 值2 … 值n)
其中,各个值之间以空格分开。
2.5.3 变量引用
有效的变量引用表达式有以下形式:
$name ${name#pattern}
${name} ${name##pattern}
${name[n]} ${name % pattern}
${name[*]} ${name %% pattern}
${name [@]}
${#@}和${#*}
①表达式$name表示变量name的值,若变量未定义,则用空值替换。
②表达式${name}将变量name的值替换。用花括号括起name,目的在于把变量名与后面的字符分隔开,避免出现混淆。替换后花括号被取消。
③${name[n]}表示数组变量name中第n个元素的值。
④表达式${name[*]}和${name[@]}都表示数组name中所有非空元素的值,每个元素的值用空格分开。如果用双引号把它们都括起来,那么二者的含义就有区别:对于"${name[*]}",它被扩展成一个词(即字符串),这个词由以空格分开的各个数组元素组成;对于"${name[@]}",它被扩展成多个词,每个数组元素是一个词。如果数组name中没有元素,则${name[@]}被扩展为空串。
⑤表达式${name#pattern}和${name##pattern}
如果pattern(Shell模式)与name值的开头匹配,那么name的值去掉匹配部分后的结果就是该表达式的值;否则, name的值就是该表达式的值。在第一种格式中,name值去掉的部分是与pattern匹配的最少的部分;而第二种格式中,name值去掉的部分是与pattern匹配的最多的部分。
⑥表达式${name % pattern}和${name %% pattern}
如果pattern与name值的末尾匹配,那么name的值中去掉匹配部分后的结果就是该表达式的值;否则,该表达式的值就是name的值。在第一种格式中,去掉的部分是最少的匹配部分;而第二种格式中,去掉的部分是最多的匹配部分。
⑦表达式${#@}和${#*}:它们的值分别是由$@和$*返回的参数的个数。
⑧表达式${#name[i]}:该表达式的值是数组name第i个元素值的长度(字符个数)。
⑨表达式${#name[*]}和${#name[@]}
它们的值都是数组name中已经设置的元素的个数。
2.5.4 输入/输出命令
1.read命令
功能:利用read命令从键盘上读取数据,然后赋给指定的变量。
格式:read 变量1 [ 变量2 …]
2. echo命令
功能:显示其后的变量值或者直接显示它后面的字符串
【例4.6】 这是一个特洛伊木马shell脚本示例。
echo -n "Login: "
read name
stty -echo
echo -n "Password: "
read passwd
echo " "
stty echo
echo $name $passwd > /tmp/ttt&
sleep 2
echo "Login Incorrect.Re-enter, Please. "
(代码安全意识、社会责任、价值观、诚信和职业道德)
2.5.5 位置参数
1.位置参数及其引用
位置变量的名称很特别,分别是0,1,2,…
命令行实参与脚本中位置变量的对应关系如下所示:
exam1 m1 m2 m3 m4
$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11}
引用它们的方式依次是$0, $1, $2, …, $9, ${10}, ${11}等。
其中,$0始终表示命令名或shell脚本名。
▲位置变量不能通过一般赋值的方式直接赋值
▲通过命令行上对应位置的实参传值——教材例4.7
2.用set命令为位置参数赋值
2.5.6 移动位置参数
每执行一次shift命令,就把命令行上的实参向左移一位,即相当于位置参数向右移动一个位置。
命令行: ex7 A B C D E F
原位置参数: $0 $1 $2 $3 $4 $5 $6
移位后位置参数: $0 $1 $2 $3 $4 $5
2.5.7 预先定义的特殊变量
2.5.8 环境变量
常用的环境变量:
- HOME:用户主目录的全路径名
- LOGNAME:即你的注册名,由Linux自动设置
- MAIL: 你的系统信箱的路径
- PATH: shell从中查找命令的目录列表。可以设置它,如:PATH=$PATH:$HOME/bin
- PWD:你当前工作目录的路径
- SHELL:你当前使用的shell
- TERM: 你的终端类型
使用环境变量:
如果要使用环境变量或其它shell变量的值,必须在变量名之前加上一个“$”符号,不能直接使用变量名,如:cd $HOME
删除环境变量:
$ unset NAME
2.5.9 环境文件
bash的环境文件包括.bash_profile文件、.bashrc文件、.bash_logout文件等。
在.bash_profile中,设置了环境变量和文件掩码(umask)
名为.bashrc的脚本,每次启动bash时便会执行它。它只含有针对bash的命令,可以用来设置别名。.bashrc在.bash_profile之后执行
.bash_logout,它仅在退出注册的时候运行
2.5.10 export语句与环境设置
1.export语句
一个进程在自己的环境中定义的变量是局部变量,仅限于自身范围,不能自动传给其他进程。就是说,其他进程只能访问该进程的公用区和转出区中的数据,而每个进程的数据区和栈区是私有的。为了使其他进程能访问该进程中定义的变量,就必须用export(转出)命令将这些变量送入进程转出区。
2.环境变量的设置和显示
例如:$ PS1="OK> "
export HOME HZ LOGNAME TERM
2.6 算数运算
bash中执行整数算术运算的命令是let,其语法格式为:
let arg …
其中arg是单独的算术表达式。它使用C语言中表达式的语法、优先级和结合性。除++、--和逗号(,)之外,所有整型运算符都得到支持,此外,还提供了方幂运算符“**”。
let 命令的替代表示形式是:
((算术表达式))
例如:
let ″j=i*6+2″ 等价于 ((j=i*6+2))
注意:
2.7 控制结构
2.7.1 if语句
if 测试条件
then 命令1
else 命令2
fi
if test -f "$1"
then echo "$1 is an ordinary file . "
else echo "$1 is not an ordinary file . "
fi
if test -f "$1"
then echo "$1 is an ordinary file . "
fi
if test - f "$1"
then pr $1
elif test - d "$1"
then ( cd $1 ; pr * )
else echo "$1 is neither a file nor a directory . "
fi
if 命令表1
then 命令表2
else 命令表3
fi
2.7.2 条件测试
条件测试有三种常用形式:
(1) 一种是用test 命令
(2) 用一对方括号将测试条件括起来
例如,测试位置参数$1是否是已存在的普通文件,可写为:
test -f “$1“ 等价于 [ -f "$1" ]
(3) [[条件表达式]]
有关文件方面的测试:
参 数 | 功 能 |
-r 文件名 | 若文件存在并且是用户可读的,则测试条件为真 |
-w 文件名 | 若文件存在并且是用户可写的,则测试条件为真 |
-x 文件名 | 若文件存在并且是用户可执行的,则测试条件为真 |
-f 文件名 | 若文件存在并且是普通文件,则测试条件为真 |
-d 文件名 | 若文件存在并且是目录文件,则测试条件为真 |
-b 文件名 | 若文件存在并且是块设备文件,则测试条件为真 |
-c 文件名 | 若文件存在并且是字符设备文件,则测试条件为真 |
-s 文件名 | 若文件存在并且文件的长度大于0,则测试条件为真 |
有关字符串方面的测试:
参 数 | 功 能 |
-z s1 | 如果字符串s1的长度为0,则测试条件为真。 |
-n s1 | 如果字符串s1的长度大于0,则测试条件为真。 |
s1 | 如果字符串s1不是空字符串,则测试条件为真。 |
s1 = s2 | 如果s1等于s2,则测试条件为真。“=”也可以用“==” 代替。在“=”前后应有空格。 |
s1 != s2 | 如果s1不等于s2,则测试条件为真。 |
s1 < s2 | 如果按字典顺序s1在s2之前,则测试条件为真 |
s1 > s2 | 如果按字典顺序s1在s2之后,则测试条件为真 |
有关数值方面的测试:
参 数 | 功 能 |
n1 -eq n2 | 如果整数n1等于n2,则测试条件为真 |
n1 -ne n2 | 如果整数n1不等于n2,则测试条件为真 |
n1 -lt n2 | 如果n1小于n2,则测试条件为真 |
n1 -le n2 | 如果n1小于或等于n2,则测试条件为真 |
n1 -gt n2 | 如果n1大于n2,则测试条件为真 |
n1 -ge n2 | 如果n1大于或等于n2,则测试条件为真 |
逻辑运算符:
上述测试条件可以在if 语句或循环语句中单个使用,也可以通过逻辑运算符把它们组合起来使用。可以在测试语句中使用的逻辑运算符有:
[ ! -r $1 ] , ! test -r “$1”等。
[ - f “$myfile” - a - r “$myfile" ]
[ "$a" -ge 0 -o "$b" -le 100 ]
[ \( "$a" -ge 0 \) -a \( "$b" -le 100 \) ]
特殊条件测试:
(1) :表示不做任何事情,其退出值为0。
(2)true 表示总为真,其退出值总是0。
(3)false 表示总为假,其退出值是255。
2.7.3 while语句
shell中有三种用于循环的语句,它们是:while语句、for语句和until语句。
while语句的一般形式是:
while 测试条件
do
命令表
done
测试条件部分除使用test命令或等价的方括号外,还可以是一组命令。根据其最后一个命令的退出值决定是否进入循环体执行。
2.7.4 until语句
until语句的一般形式是:
until 测试条件
do
命令表
done
它与while语句很相似,只是测试条件不同:当测试条件为假时,才进入循环体,直至测试条件为真时终止循环。
2.7.5 for语句
主要有两种方式:一种是值表方式,另一种是算术表达式方式。
1.值表方式
其一般格式是:for 变量 [ in 值表 ];do 命令表;done
根据循环变量的取值方式,其使用格式可分为三种:
(1) 格式一:
for 变量 in 值表
do
命令表
done
(2) 格式二:
for 变量 in 文件正则表达式(如依次取目录下所有匹配文件名)
do
命令表
done
(3) 格式三:
for i in $* (取全部位置参数) 或者 for i
do do
命令表 命令表
done done
右边省略了关键字in和位置参数$*,但是两种是等价的!
2.算术表达式方式
其一般格式是:
for ((e1;e2;e3))
do
命令表
done
其中,e1, e2, e3是算术表达式。它的执行过程与C语言中for语句相似,即:① 先按算术运算规则计算表达式e1;② 接着计算e2,如果e2值不为0,则执行命令表中的命令,并且计算e3;然后重复②,直至e2为0,退出循环。
2.7.6 break命令和continue命令
1.break命令
break命令使程序从循环体中退出来。其语法格式是:
break [ n ]
2.continue命令
continue命令跳过循环体中在它之后的语句,回到本层循环的开头,进行下一次循环。其语法格式是:
continue [ n ]
2.7.7 exit命令
exit命令的功能是立即退出正在执行的shell脚本,并设定退出值。其语法格式是:
exit [ n ]
2.8 函数
在shell脚本中可以定义并使用函数。其定义格式为:
[function]函数名( )
{
命令表
}
函数应先定义,后使用。调用函数时,直接利用函数名,如showfile,不必带圆括号
shell脚本与函数间的参数传递可利用位置参数和变量直接传递
通常,函数中的最后一个命令执行之后,就退出被调函数。也可利用return命令立即退出函数,其语法格式是:return [ n ]
2.9 shell脚本调试
通常采用自底向上的方法,即:先搞清楚要脚本做什么,然后将过程的连续阶段分解为独立的步骤,最后利用shell提示符,交互式地检查和调试每个独立的步骤。
编写的脚本无法执行的原因除脚本文件缺少“执行”权限外,有两种可能:执行脚本的环境设置不对和脚本本身有错误。
2.9.1 解决环境设置问题
环境变量不对是指运行脚本的环境不是为该脚本设置的!
① 不能直接在其他shell下运行bash脚本。
解决的办法是在脚本的第一行写上:#!/bin/bash
② 在PATH环境变量中没有包括“.”(当前工作目录)。
解决办法是设置PATH:PATH=$PATH:.
③ 脚本文件与已存在命令的名字相同。
2.9.2 解决脚本错误
基本的错误类型有两种:语法错误和逻辑错误。
(1)语法错误是编写程序时违反了所用编程语言的规则而造成的。
(2)逻辑错误通常是由于程序的逻辑关系存在问题。对此类问题需要进行程序调试。