一、命令详解
1.1、命令说明
一条shell命令包含三个要素:命令名称、选项、参数,格式如下:
# 注意 $表示普通用户,#代表超级用户;
# command命令严格区分大小写
# ptions参数由"-"引导
$ command [options] argument1 argument1
# 另外
# 一条命令的三要素用空格隔开
# 若将多个命令在一行书写,用分号';‘ 隔开
# 如果一条命令不能在一行写完,在行尾使用反斜杠 \ 标明该条命令还未结束
1.2、别名、函数、内置命令、程序执行顺序
一个命令的别名(alias)、函数(function),内置命令(builtin)和程序(program)的执行优先次序
先 alias --> function --> builtin --> program 后
验证:
#把test命名为ls -l的别名
$ alias test="ls -l"
#执行test命令 ,结果表明优先执行alias
[root@iZbp18i0nt28c8wyrod16yZ ~]# test
total 16
drwxr-xr-x 3 root root 4096 Aug 2 17:17 fanwh
drwxr-xr-x 8 root root 4096 Aug 2 15:36 oneinstack
-rw-r--r-- 1 root root 475 Aug 2 15:36 ReadMe
drwxr-xr-x 2 root root 4096 Aug 2 18:27 tmp
##############################################################
#定义一个function
[root@iZbp18i0nt28c8wyrod16yZ ~]# function test { echo "hi, I'm a function"; }
#再次执行发现还是执行的alias
[root@iZbp18i0nt28c8wyrod16yZ ~]# test
total 16
drwxr-xr-x 3 root root 4096 Aug 2 17:17 fanwh
drwxr-xr-x 8 root root 4096 Aug 2 15:36 oneinstack
-rw-r--r-- 1 root root 475 Aug 2 15:36 ReadMe
drwxr-xr-x 2 root root 4096 Aug 2 18:27 tmp
##############################################################
# 删除alias,再次执行发现执行的是function
[root@iZbp18i0nt28c8wyrod16yZ ~]# unalias test
[root@iZbp18i0nt28c8wyrod16yZ ~]# test
hi, I'm a function
##############################################################
# 如果要执行内置test命令
[root@iZbp18i0nt28c8wyrod16yZ ~]# builtin test
##############################################################
# 使用type查看可以发现命令执行优先级
[root@iZbp18i0nt28c8wyrod16yZ ~]# type -a test
test is aliased to `ls -l'
test is a function
test ()
{
echo "hi, I'm a function"
}
test is a shell builtin
test is /usr/bin/test
##############################################################
1.3、/bin/bash的启动
我们知道/bin/bash由/bin/login启动;那么/bin/login如何知道应该启动哪个bash?实际上/bin/login程序会检查我们的/etc/passwd文件,在这个文件里头包含了用户名、密码和该用户的登录shell。密码和用户名匹配用户的登录,而登录shell则作为用户登录后的命令行程序。
可通过/etc/passwd文件查看当前用户的登录shell:
[root@iZbp18i0nt28c8wyrod16yZ ~]# cat /etc/passwd | grep root
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
#其中x表示密码被保护,存放在/etc/shadow文件,当然是加密的。
# 整体而言: /sbin/init -> /bin/login - > /bin/bash
# 进一步细化 : fork execve execve fork execve
# init --> init --> /sbin/getty --> /bin/login --> /bin/login --> /bin/bash
1.4、strace查看命令执行过程
查看命令执行情况,并输出到strace.out文件;例如 查看bin/login命令的执行
strace -f -o strace.out /bin/login
1.5、type查看命令类型及命令如何被执行
如查看test命令的执行,详情可查看命令手册man type
[root@iZbp18i0nt28c8wyrod16yZ kooder]# type test
test is a shell builtin
1.6、同命令不同path
先看看PATH环境变量,确保它有/usr/bin,/bin和/usr/local/sbin这几个目录,然后通过type -P(-P参数强制到PATH下查找,而不管是别名还是内置命令等,可以通过help type查看该参数的含义)查看,到底哪个先被执行
$ echo $PATH
[root@iZbp18i0nt28c8wyrod16yZ ~]# echo $PATH
/usr/local/nginx/sbin:/usr/local/php/bin:/usr/local/mysql/bin:/usr/local/java/jdk1.8.0_211/bin:/root/fanwh/kooder/apache-maven-3.9.3//bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
# 规律如下:
#shell从PATH列出的路径中依次查找用户输入的命令。考虑到程序的优先级最低,如果想优先执行磁盘上的程序文件test呢?
#那么就可以用test -P找出这个文件并执行就可以了
1.7、重定向
重定向操作符: >,<,>>,<<,<>,|
# >>在输出时追加到文件末尾,而>则会从头开始写入文件,前者意味着文件的大小会增长,而后者则意味文件被重写
# <字符表示:把test.c文件重定向为标准输入,作为cat命令的输入,而cat默认把内容输出到标准输出。
$ cat < ./test.c
# >表示把标准输出重定向为文件test_new.c,结果内容输出到test_new.c
$ cat < ./test.c > test_new.c
#| 被形象地称为“管道”,实际上它就是通过C语言里头的无名管道来实现的,如下列命令,只打印了包含hi的字符串行
$ cat < ./test.c | grep hi
#管道如何实现? 它通过C语言里头的pipe函数创建了一个管道(一个包含两个文件描述符的整形数组,
#一个描述符用于写入数据,一个描述符用于读入数据),并且通过 dup/fcntl把cat的输出复制到了管道的输入,
#而把管道的输出则复制到了grep的输入。这真是一个奇妙的想法。
# & 当你在程序的最后跟上这个奇妙的字符以后就可以接着做其他事情了,例如下列代码让程序在后台运行
$ sleep 50 &
#在命令的后面加上&后,该命令将被作为后台进程执行,后台进程是什么呢?
#这类进程无法接收用户发送给终端的信号(如 SIGHUP,SIGQUIT,SIGINT),无法响应键盘输入(被前台进程占用着),
#不过可以通过fg切换到前台而享受作为前台进程具有的特权。
二、字符串
2.1、字符串定义
单引号 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的
[root@iZbp18i0nt28c8wyrod16yZ kooder]# name='hello $'
[root@iZbp18i0nt28c8wyrod16yZ kooder]# echo name
name
双引号 可以在双引号中使用变量;可以在双引号中使用转义字符
[root@iZbp18i0nt28c8wyrod16yZ kooder]# name="hallo";
[root@iZbp18i0nt28c8wyrod16yZ kooder]# echo "my name is ${name}";
my name is hallo
2.2、字符串长度
#使用 #取字符串长度
[root@iZbp18i0nt28c8wyrod16yZ kooder]# echo ${string}
abcd
[root@iZbp18i0nt28c8wyrod16yZ kooder]# echo ${#string}
4
2.3、字符串截取
# 截取字符串,
[root@iZbp18i0nt28c8wyrod16yZ kooder]# string="this is a text"
[root@iZbp18i0nt28c8wyrod16yZ kooder]# echo ${string:2:6}
is is
2.4、字符索引位置查询
查找字符串中首次出现的位置,多个字符时,显示第一个字符出现的位置
[root@iZbp18i0nt28c8wyrod16yZ kooder]# string="this is a text"
[root@iZbp18i0nt28c8wyrod16yZ kooder]# echo `expr index "$string" i`
3
三、数组
3.1、数组定义与读取
# 数组定义,常用
[root@iZbp18i0nt28c8wyrod16yZ kooder]# array_name=(value1 value2 value3 value4)
# 读取所有元素
[root@iZbp18i0nt28c8wyrod16yZ kooder]# echo ${array_name[@]}
value1 value2 value3 value4
[root@iZbp18i0nt28c8wyrod16yZ kooder]# echo ${array_name[*]}
value1 value2 value3 value4
# 读取数组长度
[root@iZbp18i0nt28c8wyrod16yZ kooder]# echo ${#array_name[*]}
4
[root@iZbp18i0nt28c8wyrod16yZ kooder]# echo ${#array_name[@]}
4
# 取指定索引位置元素长度
[root@iZbp18i0nt28c8wyrod16yZ kooder]# echo ${#array_name[0]}
6
四、参数
4.1、脚本传参
在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n。n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推……,
[root@iZbp18i0nt28c8wyrod16yZ kooder]# vim test.sh
# 编辑test.sh内容如下:
# echo "传递参数实例!";
# echo "执行的文件名:$0";
# echo "第一个参数为:$1";
# echo "第二个参数为:$2";
# echo "第三个参数为:$3";
[root@iZbp18i0nt28c8wyrod16yZ kooder]# chmod +x test.sh
[root@iZbp18i0nt28c8wyrod16yZ kooder]# ./test.sh a b c
#输出结果
# 传递参数实例!
# 执行的文件名:./test.sh
# 第一个参数为:a
# 第二个参数为:b
# 第三个参数为:c
4.2、参数处理
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数。 如”$*“用「”」括起来的情况、以”$1 $2 … $n”的形式输出所有参数。
$$ 当前进程ID号
$! 取上一条指令的PID;后台运行的最后一个进程的ID号
$@ 与∗ 相 同 , 但 是 使 用 时 加 引 号 , 并 在 引 号 中 返 回 每 个 参 数 。 如 ” *相同,但是使用时加引号,并在引号中返回每个参数。 如”∗相同,但是使用时加引号,并在引号中返回每个参数。如”@“用「”」括起来的情况、以”$1″ “2 ” … ” 2″ … “2”…”n” 的形式输出所有参数。
$- 显示Shell使用的当前选项,与set命令功能相同。
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。
4.3、算术运算
shell中不支持简单的数学运算,如使用算符运算符就需要搭配的常用的工具有两种 1、awk 暂不做分析 2、expr (使用频繁)
#运算规则注意:
#表达式和运算符之间必须要有空格,例如 3+2 是不对的,必须写成 3 + 2
#完整的表达式要被 两个” ` “包含(在 Esc 键下边那个键)
#在windows系统中乘号(*)前边必须加反斜杠()才能实现乘法运算
var=`expr 2 + 3`
echo $var
4.4、关系运算
shell中的关系运算符和其他编程语言不同,shell中使用特殊的字符表示关系运算符,并且只支持数字,不支持字符串,除非字符串是数字。注意 运算符和数之间必须要用空格隔开
运算规则如下:
# 检测两个数是否相等,相等返回 true;如 [ $a -eq $b ] 返回 false。
-eq
# 检测两个数是否不相等,不相等返回 true;如[ $a -ne $b ] 返回 true。
-ne
# 检测左边的数是否大于右边的,如果是,则返回 true;如[ $a -gt $b ] 返回 false。
-gt
# 检测左边的数是否小于右边的,如果是,则返回 true;[ $a -lt $b ] 返回 true。
-lt
# 检测左边的数是否大于等于右边的,如果是,则返回 true;[ $a -ge $b ] 返回 false。
-ge
# 检测左边的数是否小于等于右边的,如果是,则返回 true;[ $a -le $b ] 返回 true。
-le
4.5、逻辑与布尔运算
# 非运算,表达式为 true 则返回 false,否则返回 true;[ ! false ] 返回 true。
!
# 或运算,有一个表达式为 true 则返回 true;[ $a -lt 20 -o $b -gt 100 ] 返回 true。
-o
# 与运算,两个表达式都为 true 才返回 true;[ $a -lt 20 -a $b -gt 100 ] 返回 false。
-a
# 逻辑的 AND[[ $a -lt 100 && $b -gt 100 ]] 返回 false
&&
# 逻辑的 OR [[ $a -lt 100 || $b -gt 100 ]] 返回 true
||
# 注意 这里使用两层的[ ]符号,将两次关系运算的结果保存在条件句中
4.6、字符串运算
# 检测两个字符串是否相等,相等返回 true;[ $a = $b ] 返回 false。
=
# 检测两个字符串是否相等,不相等返回 true;[ $a != $b ] 返回 true。
!=
# 检测字符串长度是否为0,为0返回 true;[ -z $a ] 返回 false。
-z
# 检测字符串长度是否不为 0,不为 0 返回 true;[ -n “$a” ] 返回 true。
-n
# 检测字符串是否为空,不为空返回 true;[ $a ] 返回 true。
$
4.7、文件测试运算符
shell中的文件测试运算符用于检测在类unix系统中,文件的各种属性
# 检测文件是否是块设备文件,如果是,则返回 true ; [ -b $file ] 返回 false。
-b file
# 检测文件是否是字符设备文件,如果是,则返回 true;[ -c $file ] 返回 false。
-c file
# 检测文件是否是目录,如果是,则返回 true;[ -d $file ] 返回 false。
-d file
# 检测文件是否是普通文件(既不是目录,也不是设备文件),如果是,则返回 true;[ -f $file ] 返回 true。
-f file
# 检测文件是否设置了 SGID 位,如果是,则返回 true;[ -g $file ] 返回 false。
-g file
# 检测文件是否设置了粘着位(Sticky Bit),如果是,则返回 true;[ -k $file ] 返回 false。
-k file
# 检测文件是否是有名管道,如果是,则返回 true;[ -p $file ] 返回 false。
-p file
# 检测文件是否设置了 SUID 位,如果是,则返回 true;[ -u $file ] 返回 false。
-u file
# 检测文件是否可读,如果是,则返回 true;[ -r $file ] 返回 true。
-r file
# 检测文件是否可写,如果是,则返回 true;[ -w $file ] 返回 true。
-w file
# 检测文件是否可执行,如果是,则返回 true;[ -x $file ] 返回 true。
-x file
# 检测文件是否为空(文件大小是否大于0),不为空返回 true;[ -s $file ] 返回 true。
-s file
# 检测文件(包括目录)是否存在,且至少有一个字符则为真;如果是,则返回 true;[ -e $file ] 返回 true。
-e file
五、echo与printf
echo
echo -e "Right!\n " # -e 表示开启转义
echo "this is a test" > testfile
printf
# 警告字符,通常为ASCII的BEL字符
\a
# 后退
\b
# 抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略
\c
# 换页(formfeed)
\f
# 换行
\n
# 回车(Carriage return)
\r
# 水平制表符
\t
# 垂直制表符
\v
# 一个字面上的反斜杠字符
\
# 表示1到3位数八进制值的字符。仅在格式字符串中有效
\ddd
# 表示1到3位的八进制值字符
\0ddd
六、test
test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试
# 等于则为真,如: if test $[a] -eq $[a] then
-eq
# 不等于则为真,如: if test $[a] -ne $[a] then
-ne
# 大于则为真,如:if test $[a] -gt $[a] then
-gt
# 大于等于则为真,如:if test $[a] -ge $[a] then
-ge
# 小于则为真,如:if test $[a] -lt $[a] then
-lt
# 小于等于则为真,如:if test $[a] -le $[a] then
-le
七、流程控制
7.1、if-else
#if-else格式模板
if - then - fi
# if-elseif格式模板
if -then elif then - fi
7.2、case
用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令
case 值 in
模式1)
command1
commandN
;;
模式2)
command1
commandN
;;
esac
需要注意
# 取值后面需要加上in
# 每一模式必须以右括号结束
# 每个模式结束后使用;;符号结尾
# 如果没有找到对应的模式。以*结尾,并跳出case
# case需要搭配esac结尾,与C语言中的switch … case语句类似
# demo如下
echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read num
case $num in
1) echo '你选择了 1'
;;
2) echo '你选择了 2'
;;
3) echo '你选择了 3'
;;
4) echo '你选择了 4'
;;
*) echo '你没有输入 1 到 4 之间的数字'
;;
esac
# 与其他语言类似,case中想要跳出循环有两个命令:break和continue
# break命令:允许跳出所有循环(中止执行后面所有的循环)
7.3、for循环
for循环调用格式和python中的for循环有点类似
for var in item1 item2 ... itemN
do
command1
...
commandN
done
# in列表中可以包含替换、字符串和文件名等
# in列表是可选的,如果默认不适用,将会循环使用命令行中的位置参数
7.4、while
while循环
while condition
do
command
done
# 如
num = 1
while(( $num<=5 ))
do
echo $num
let "num++"
done
使while循环进行判定或者判断键盘循环,甚至无限循环
echo '按下 <Q> 退出'
echo -n '输入你最喜欢的歌名: '
while read SONG
do
echo "啊!$SONG 真是一首好歌"
done
7.5、until循环
until 循环执行一系列命令直至条件为 true 时停止。until 循环与 while 循环在处理方式上刚好相反。一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用,语法格式如下:
until condition
do
command
done
# demo如下:
a=0
until [ ! $a -lt 5 ]
do
echo $a
a=`expr $a + 1`
done
八、函数
8.1、定义函数
函数定义模板
[ function ] funname [()]
{
action;
[return int;]
}
function fun () 表示有返回参数的函数(如同C语言中的有返回类型的函数(int,char等))
fun() 表示无返回参数的函数(类似于C语言中的void类型函数)
使用return可以返回参数值(一般为数值n),如果不使用,将默认以最后一条命令运行的结果作为返回值,举例如下:
FunReturn(){
echo "两个数字进行相加运算..."
echo "输入第一个数字: "
read num
echo "输入第二个数字: "
read anothernum
echo "两个数字分别为 $num 和 $anothernum !"
return $(($num+$anothernum)) # 分别返回数值
}
FunReturn # 调用函数
echo "输入的两个数字之和为 $? !" # 使用通配符获取上一条指令的返回值;$?前面我们讲过,用来返回上一条指令执行后的状态值,一般为0-255,这里可以理解为暂用
8.2、函数参数定义
使用shell函数传递参数时,需要在函数体的内部,通过 n的形式来获取参数的值,与其他语言不同的是,这不是在定义函数的时候就给定参数,而是在函数体中获取到的参数,例如,1表示第一个参数
#demo举例
#!/bin/bash
FunParam(){
echo "输入第一个参数 $1 !"
echo "输入第二个参数 $2 !"
echo "输入第十个个参数 $10 !"
echo "参数总数共 $# 个!"
echo "作为一个字符串输出所有参数 $* !"
}
FunParam 1 2 3 4 5 6 7 8 9 10
九、重定向
9.1、通配符
用于处理查找一组名称类型相同的文件,提高效率
通配符 | 含义 | 举例 |
---|---|---|
星号(*) | 匹配任意长度的字符串 | 用ddd_*.txt,匹配ddd_zhang.txt,ddd_le.txt,ddd_wang.txt等同类型文件 |
问号(?) | 匹配一个长度的字符 | 用ddd_?.txt,匹配ddd_1.txt,ddd_2.txt,ddd_3.txt文件 |
方括号([…]) | 匹配其中指定的一个字符 | 用ddd_[otr].txt,匹配ddd_o.txt,ddd_t.txt,ddd_r.txt特定字符 |
方括号([ - ]) | 匹配指定的一个字符范围 | 用ddd_[a-z].txt,匹配ddd_a.txt,ddd_b.txt,ddd_c.txt,… ,ddd_z.txt范围内的字符 |
方括号([^ …) | 除了其中指定的单个字符,均可匹配 | 用ddd_[ ^ otr ].txt,匹配除了ddd_o.txt,ddd_t.txt,ddd_r.txt特定字符以外的其他字符 |
9.2、管道
管道可以将一些列命令连接起来,表示为第一个命令的输出将作为第二个命令的输入,通过管道传递给第二个命令,第二个命令的输出又作为第三个命令的输入,以此类推,通常使用"|"符号连接命令管道;执行管道命令只需要知道前一个命令的结果类型和下一个命令的入参类型即可.
# 举例 ls,统计ls的结果大小单位byte,具体wc命令推荐使用man手册查看
ls | wc -c
# 可以使用 ls > ls_result.txt,查看ls执行后的结果值
9.3、I/O重定向
Linux中的默认的标注输入定义为从键盘输入,标准输出定义为从终端窗口输出;用于为当前操作改变输入或者输出,迫使某人特定命令的输入或者输出来源为外部文件
重定向符号 | 含义 | 实例 |
---|---|---|
>file | 将file文件重定向为输出源,新建模式 | ls /usr >lsoutput.txt,将ls /usr命令的执行结果,写到lsoutput.txt中去,如没有此文件将新建,若存在此文件,将覆盖 |
>>file | 将file文件重定向为输出源,追加模式 | ls /usr >>lsoutput.txt,将ls /usr命令的执行结果,追加到lsoutput.txt文件已有的内容之后 |
<file | 将file文件重定向为输入源 | wc < file1,将file1中的内容作为输入源传给wc命令 |
2>或&> | 将由命令产生的错误信息输入到文件中 | ls notexistfile.txt 2>err.log,使用ls命令查看一个不存在的文件名的时候,将系统错误信息提示保存在err.log文件中 |
10、命令替换
10.1、通过vim编辑器来替换
# vi/vim 中可以使用 :s 命令来替换字符串。
:s/well/good/ 替换当前行第一个 well 为 good
:s/well/good/g 替换当前行所有 well 为 good
:n,$s/well/good/ 替换第 n 行开始到最后一行中每一行的第一个 well 为 good
:n,$s/well/good/g 替换第 n 行开始到最后一行中每一行所有 well 为 good n 为数字,若 n 为 .,表示从当前行开始到最后一行
:%s/well/good/(等同于 :g/well/s//good/) 替换每一行的第一个 well 为 good
:%s/well/good/g(等同于 :g/well/s//good/g) 替换每一行中所有 well 为 good 可以使用 # 作为分隔符,此时中间出现的 / 不会作为分隔符
:s#well/#good/# 替换当前行第一个 well/ 为 good/
:%s#/usr/bin#/bin#g 可以把文件中所有路径/usr/bin换成/bin
10.2、sed和grep配合
#将当前目录(包括子目录)中所有txt文件中的yyyy字符串替换为xxxx字符串
[root@iZbp18i0nt28c8wyrod16yZ ~]#sed -i s/yyyy/xxxx/g `grep yyyy -rl --include="*.txt" ./`
#命令解释:
# -i表示操作的是文件
# s/yyyy/xxxx/g 替换所有行中的yyyy为xxxx,g表示替换所有
# `grep yyyy -rl --include="*.txt" ./` ,表示将grep命令的的结果作为操作文件
#仅需替换当前目录下,则直接使用即可
[root@iZbp18i0nt28c8wyrod16yZ ~]#sed -i s/xxxx/yyyy/g ./*.txt
10.3、find命令查找和替换
查找替换当前目录下包含字符串并进行替换
find -name '要查找的文件名' | xargs perl -pi -e 's|被替换的字符串|替换后的字符串|g'
#命令解释
# -name 需要查找的文件名
# xargs 从标准输入构建并执行命令行
# perl Perl 5 language interpreter
# -p
99、参考资料
:http://www.cppblog.com/cuijixin/archive/2008/03/14/44463.html