简介
什么是"shell"
Shell是命令解释器,是Unix操作系统的用户接口,程序从用户接口接收到输入信息,shell将用户程序及其输入翻译成操作系统内核能够识别的指令,并且操作系统内核执行完将返回的输出通过shell再展示给用户
简单来说:shell就是一个用户跟操作系统之间交互的命令解释器
什么是"shell"脚本
简单来说:"shell"脚本就是一种包含有一个或多个"unix"命令的可执行的"text"类型的文件,不需要编译就可以直接执行
系统支持的shell
1、查看当前系统支持的shell (chsh -l 输出文件/etc/shells内容)
[root@ /cdly/shell]# cat /etc/shells
/bin/sh
/bin/bash
/sbin/nologin
/usr/bin/sh
/usr/bin/bash
/usr/sbin/nologin
/bin/tcsh
/bin/csh
2、查看当前环境下使用的shell: echo $0、echo $SHELL
[root@ /cdly/shell]# echo $0
-bash
[root@ /cdly/shell]# echo $SHELL
/bin/bash
[root@ /cdly/shell]#
[root@ /cdly/shell]# w
21:09:24 up 2:26, 1 user, load average: 0.00, 0.00, 0.00
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/0 192.168.126.1 20:52 0.00s 0.11s 0.00s w
[root@ /cdly/shell]# grep root /etc/passwd
root:x:0:0:root:/root:/bin/bash
Bash功能介绍
1、补全命令功能(Tab)
1、由于Linux系统的命令数量比较多,这么多的命令要记住并不容易,因此就需要一种能够记住这些命令的功能,这个功能在bash上就是咱们的命令补全功能。
2、命令补全是一个非常有用的功能,有了它就只需要记住命令的开始部分而不需要记住全部,给咱们日常管理带来极大便利性。
3、在bash上要补全命令,可通键盘上的Tab键来实现,
4、小技巧:如果按一次Tab键没有输出补全或提示,那就连续按两次;如果连续按多次依然没有补全或输出,那就说明系统没有这个命令,或需要安装相关的软件包才有
2、命令历史
1、bash拥有自动记录命令历史的功能,用户当前操作的命令会在用户注销时自动记录到自己的家目录下的隐藏文件~/.bash_history
2、通过键盘的上下方向键就可以查找到历史的命令,也可以使用历史命令history命令来查看
3、历史命令需要了解2个对应的环境变量:
HISTSIZE 历史命令记录的行数
HISTFILE 历史命令文件保存位置,默认是~/.bash_history
3、命令别名
定义一个别名时,需要使用到alias命令,比如咱们常见的ll;系统里面没有ll这个命令,只是进行别名定义,因此咱们才可以在终端上进行使用
注意:脚本内默认是无法使用别名定义的,即也无法使用ll,这个大家要注意
用处:使用别名的好处就是可以把本来很长的指令简化缩写,如:alias tmp_l_e='ls file.txt ;echo 000000;touch test.txt;ls'
4、快捷键
快捷键 | 描述 |
Ctrl + L(l) | 清屏 |
Ctrl + A(a) | 把当前命令行光标跳转至行首 |
Ctrl + E(e) | 把当前命令行光标跳转至行尾 |
Ctrl + U(u) | 删掉当前光标位置到行首之间的字符串内容 |
Ctrl + K(k) | 删掉当前光标位置到行尾之间的字符串内容 |
Ctrl + C(c) | 终止当前作业 |
Ctrl + D(d) | 结束符,可用于退出当前shell或者结束当前输入 |
Ctrl + R(r) | 在命令历史内查找匹配最近操作的命令,并显示执行 |
Ctrl + Z(z) | 将当前运行的程序放入后台并停止运行 |
Linux系统运行级别
Sysvinit运行级别 0-6 主要用于CentOS6.x、CentOS5.x版本的系统
Systemd目标名称 runlevel[0-6].target 主要用于CentOS7.x版本的系统
# 修改运行级别时只需要将软链接进行修改即可: ln -sf /lib/systemd/system/xxxx.target /etc/systemd/system/default.target
[root@ /cdly/shell]# ll /etc/systemd/system/default.target # CentOS7.x 默认运行级别
lrwxrwxrwx. 1 root root 37 4月 21 2016 /etc/systemd/system/default.target -> /lib/systemd/system/multi-user.target
[root@ /cdly/shell]# ll /lib/systemd/system/runlevel*.target # CentOS7.x 存在的运行级别
lrwxrwxrwx 1 root root 15 11月 23 2020 /lib/systemd/system/runlevel0.target -> poweroff.target
lrwxrwxrwx 1 root root 13 11月 23 2020 /lib/systemd/system/runlevel1.target -> rescue.target
lrwxrwxrwx 1 root root 17 11月 23 2020 /lib/systemd/system/runlevel2.target -> multi-user.target
lrwxrwxrwx 1 root root 17 11月 23 2020 /lib/systemd/system/runlevel3.target -> multi-user.target
lrwxrwxrwx 1 root root 17 11月 23 2020 /lib/systemd/system/runlevel4.target -> multi-user.target
lrwxrwxrwx 1 root root 16 11月 23 2020 /lib/systemd/system/runlevel5.target -> graphical.target
lrwxrwxrwx 1 root root 13 11月 23 2020 /lib/systemd/system/runlevel6.target -> reboot.target
Sysvinit运行级别 | Systemd运行级别 | 描述 |
0 | runlevel0.target -> poweroff.target | 关机模式 |
1 | runlevel1.target -> rescue.target | 单用户模式,(修改root密码、修复系统文件) |
2 | runlevel2.target -> multi-user.target | 多用户模式,该模式下没有网络连接功能 |
3 | runlevel3.target -> multi-user.target | 多用户模式,该模式下没有网络连接功能 |
4 | runlevel4.target -> multi-user.target | 保留未使用 |
5 | runlevel5.target -> graphical.target | 保留未使用 |
6 | runlevel6.target -> reboot.target | 重启 |
Linux文件目录系统
路径 | 描述 |
/boot | 系统启动相关的文件,如内核、initrd、以及grup |
/dev | 设备文件 |
/etc | 配置文件 |
/home | 普通用户的家目录 |
/root | 管理员的家目录 |
/lib | 库文件 (静态库、.a)、(动态库、.dll、.so)、(/lib/modules:内核模块文件) |
/media | 媒体目录,临时挂载点,主要用于移动设备挂载使用 |
/mnt | 挂载目录,临时挂载点,主要用于移动设备挂载使用 |
/opt | 可选目录,常用于存放第三方软件包和数据文件 |
/proc | 进程目录,存放现有硬件及当前进程的相关信息 |
/run | 运行目录,存放系统运行时的数据 |
/srv | 服务目录,存放本地服务的相关文件 |
/sys | 系统目录,存放系统硬件信息的相关文件 |
/tmp | 临时目录,可以在该目录中创建和删除临时工作文件 |
/var | 可变目录,用以存放经常变化的文件,比如log日志文件 |
/bin | 可以执行文件,例如: 用户命令,一般普通用户都可以使用的命令 |
/sbin | 管理命令 |
/usr | 用户二进制目录 |
Linux特殊目录
类型 | 描述 |
. | 隐藏目录或代表当前目录 |
.. | 隐藏目录或代表上一层目录 |
Linux下两种路径
类型 | 描述 |
绝对路径 | 从根"/"开头的路径 |
相对路径 | 以.或者..相对比的路径(以当前位置出发的路径) |
[root@ /cdly/shell]# ll /etc/profile
-rw-r--r-- 1 root root 937 2006-01-31 /etc/profile
[root@ /cdly/shell]# cd
[root@ ~]# pwd
/root
[root@ ~]# ll ./../etc/profile
-rw-r--r-- 1 root root 937 2006-01-31 ./../etc/profile
[root@ ~]#
[root@ ~]# ll /etc/profile
-rw-r--r-- 1 root root 937 2006-01-31 /etc/profile
[root@ ~]# cd /cdly/shell/
[root@ /cdly/shell]# ll ./../../etc/profile
-rw-r--r-- 1 root root 937 2006-01-31 ./../../etc/profile
Bash变量分类
shell可以定义两类变量: 局部变量 和 环境变量
局部变量 -> 查询方式: set
环境变量 -> 查询方式: env、printenv、export(变量)、export -f(函数)、declare -x
1、本地变量
1、变量是用来存储固定值的载体,它可以具有0个或多个值,定义:变量名=值;例如:name="cdly"
2、变量定义之后使用"$变量名"来获取变量的值
3、变量名称为"字母、数字、下划线_"的组合,但首字符不能以数字开始,如:3_name=cdly
4、本地变量有称为用户自定义变量
5、作用域仅为当前shell进程
默认变量定义之后可以通过重新赋值进行修改,有以下特殊情况无法再次修改:
1、typeset -r 设置只读变量
2、declare -r 设置只读变量
取消变量赋值:unset 变量名
[root@ /cdly/shell]# name="11 22 33 44"
[root@ /cdly/shell]# echo $name
11 22 33 44
[root@ /cdly/shell]# name=`ls`
[root@ /cdly/shell]# echo $name
file.txt test.txt
[root@ /cdly/shell]# list=""
[root@ /cdly/shell]# echo $list
[root@ /cdly/shell]# echo $list_1
[root@ /cdly/shell]# _name=cdly
[root@ /cdly/shell]# echo $_name
cdly
[root@ /cdly/shell]# _name="hello $name"
[root@ /cdly/shell]# echo $_name
hello cdly
[root@ /cdly/shell]# 3_name=ceshi
-bash: 3_name=ceshi: command not found
# 取消变量赋值
[root@ /cdly/shell]# unset _name
[root@ /cdly/shell]# echo $_name
# 只读变量无法在修改原始值
[root@ /cdly/shell]# typeset -r cdly="123 qwe"
[root@ /cdly/shell]# echo $cdly
123 qwe
[root@ /cdly/shell]# cdly=file
-bash: cdly: readonly variable
[root@ /cdly/shell]# declare -r name=123
[root@ /cdly/shell]# name=cdly
-bash: name: readonly variable
2、局部变量
作用域仅为某代码片段(一般是函数体内,local var=xxx)
# 定义本地变量
[root@ /cdly/shell]# var="test"
[root@ /cdly/shell]# echo $var
test
# 函数内也定义相同的变量,默认函数内的变量也是全局的
[root@ /cdly/shell]# fun_cdly() {
> var="test - fun"
> echo $var
> }
# 函数未执行时获取的还是本地变量内容
[root@ /cdly/shell]# echo $var
test
# 函数执行后,由于函数内的变量也是全局的因此会改变var的值
[root@ /cdly/shell]# fun_cdly
test - fun
# var的值被函数内的全局修改,因此本地也会受影响
[root@ /cdly/shell]# echo $var
test - fun
# 设置函数内变量为局部变量
[root@ /cdly/shell]# fun_cdly() { local var="test - fun 局部变量"; echo $var; }
[root@ /cdly/shell]# echo $var
test - fun
# 执行函数之后,函数体内的变量变化了,因为函数体内定义的是局部变量,故函数体外的变量不受影响
[root@ /cdly/shell]# fun_cdly
test - fun 局部变量
[root@ /cdly/shell]# echo $var
test - fun
3、环境变量
1、Bash内定义了很多环境变量,在实际情况中可以直接调用这些变量
2、系统定义的环境变量名称基本上全部都是大写字母组合,如:PWD、HOME、UID、PS1......
3、系统设置的环境变量有一些是可以进行修改重新设置的,有一些则是只读(UID、EUID、PPID)不能修改
4、作用域为当前shell进程及其子进程(export var=xxx)
环境变量名称 | 描述 |
BASH | 执行当前Bash的完整路径 |
BASHPID | 当前"bash"的进程ID |
BASH_VERSION | 当前bash版本号 |
EUID | 当前登录的有效用户ID |
GROUPS | 当前用户所属组的组ID号 |
HISTSIZE | 命令历史记录的条数 |
HISTFILE | 保存shell历史记录列表的文件名 |
HOME | 当前用户的宿主目录 |
HOSTNAME | 当前主机的名称 |
IFS | 默认字段分隔符(IFS=$' \t\n') |
LANG | shell的语言环境分类 |
LOGNAME | 当前系统登录用户 |
OLDPWD | shell上一个工作目录(切换: cd -) |
PATH | 命令搜寻路径 |
PPID | "bash"父进程的PID |
PS1 | 主命令行提示符字符串 |
PS2 | 次命令行提示符字符串 |
PS3 | select命令的提示符 |
RANDOM | 返回一个0~32767之间的随机整数 |
SHELL | 环境变量保存shell的完整路径 |
TMOUT | 超时时间 |
UID | 当前登录的用户ID |
USER | 当前登录的用户名 |
[root@ /cdly/shell]# echo $HOME
/root
[root@ /cdly/shell]# echo $PWD
/cdly/shell
[root@ /cdly/shell]# echo $UID
0
[root@ /cdly/shell]# echo $PS1
[\u@ \w]\$
[root@ /cdly/shell]# echo $RANDOM
9021
[root@ /cdly/shell]# echo $LANG
zh_CN.UTF-8
[root@ /cdly/shell]# echo $PATH
/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
4、位置变量
位置变量的使用一般体现在脚本中,比如:执行shell脚本时传递的参数,一般是$1、$2.....
注意:
1、$*和$@都是表示所有的位置参数,区别在于加上双引号时"$*"将所有参数作为整体使用;"$@"->将所有参数作为个体使用
变量 | 描述 |
$0 | 脚本名字 |
$1-$n | 位置参数(n表示整数,其中十个参数之后表示:${10}) |
$# | 位置参数的个数 |
$* | 所有的位置参数("$*"将所有参数作为整体使用) |
$@ | 所有的位置参数("$@"将所有参数作为个体使用) |
${#*} | 传递到脚本中的命令行参数的个数 |
${#@} | 传递到脚本中的命令行参数的个数 |
$$ | 脚本的进程ID(PID) |
[root@ /cdly/shell]# cat test.sh
#!/bin/bash
echo "脚本名字-\$0 : $0"
echo "位置参数-\$1 : $1"
echo "位置参数-\$2 : $2"
echo "位置参数-\$3 : $3"
echo "位置参数的个数-\$# : $#"
echo "所有的位置参数-\$* : $*"
echo "所有的位置参数-\$@ : $@"
echo "命令行参数的个数-\${#*} : ${#*}"
echo "命令行参数的个数-\${#@} : ${#@}"
echo "脚本的进程PID-\$$ : $$"
[root@ /cdly/shell]# bash test.sh 11 22 33
脚本名字-$0 : test.sh
位置参数-$1 : 11
位置参数-$2 : 22
位置参数-$3 : 33
位置参数的个数-$# : 3
所有的位置参数-$* : 11 22 33
所有的位置参数-$@ : 11 22 33
命令行参数的个数-${#*} : 3
命令行参数的个数-${#@} : 3
脚本的进程PID-$$ : 17511
# "$*" 与 "$@" 区别;不加双引号时$*等价$@
[root@ /cdly/shell]# set -- "11 22" 33
[root@ /cdly/shell]# echo $1
11 22
[root@ /cdly/shell]# echo $2
33
[root@ /cdly/shell]# for i in "$*"; do echo "$i --"; done
11 22 33 --
[root@ /cdly/shell]# for i in "$@"; do echo "$i --"; done
11 22 --
33 --
[root@ /cdly/shell]# for i in $*; do echo "$i --"; done
11 --
22 --
33 --
[root@ /cdly/shell]# for i in $@; do echo "$i --"; done
11 --
22 --
33 --
5、特殊变量
shell内置的特殊变量: $?、$-、$_、$!
特殊变量名称 | 描述 |
$? | 返回值 |
$- | 传递到脚本中的标志(使用set) |
$_ | 上一个命令的最后一个参数 |
$! | 运行在后台的最后一个作业的进程PID |
# 睡眠1000秒,执行ctrl+z扔入后台
[root@ /cdly/shell]# sleep 1000
[1]+ Stopped sleep 1000
[root@ /cdly/shell]# bg
[1]+ sleep 1000 &
# 查看上一个命令执行后的返回值,0表示成功,非0表示失败
[root@ /cdly/shell]# echo $?
0
# 查看后台作业的PID
[root@ /cdly/shell]# jobs -pl
[1]+ 17631 Running sleep 1000 &
[root@ /cdly/shell]# echo $!
17631
# 获取命令的最后一个参数
[root@ /cdly/shell]# echo 11 22 33
11 22 33
[root@ /cdly/shell]# echo $_
33
# 系统预设值内容,感兴趣可以查找set、shopt 用法
[root@ /cdly/shell]# echo $-
himBH
shell中的三种引号
1、双引号("")
可以引用变量(历史命令!、变量替换$、反引号、转义符都会被正常解析,其他字符都会正常输出)
2、单引号('')
shell会忽略任何应用值,将单引号内的内容原样输出
3、反撇号(``)
将执行结果进行输出,在Bash shell中功能等同于$()
[root@ /cdly/shell]# a=test
[root@ /cdly/shell]# b=123
[root@ /cdly/shell]#
[root@ /cdly/shell]# echo "$a $b"
test 123
[root@ /cdly/shell]# echo "$a \$b"
test $b
[root@ /cdly/shell]# echo "${a}_test \$b"
test_test $b
[root@ /cdly/shell]# echo "$a_test \$b"
$b
[root@ /cdly/shell]#
[root@ /cdly/shell]# echo '$a $b'
$a $b
[root@ /cdly/shell]# !!
echo '$a $b'
$a $b
[root@ /cdly/shell]# echo '-- $a $b !! '
-- $a $b !!
[root@ /cdly/shell]# echo "-- $a $b !! "
echo "-- $a $b echo '-- $a $b !! ' "
-- test 123 echo '-- test 123 !! '
[root@ /cdly/shell]#
[root@ /cdly/shell]# ls
aa bb
[root@ /cdly/shell]# list=`ls`
[root@ /cdly/shell]# echo "$list"
aa
bb
[root@ /cdly/shell]# list_new=$(ls)
[root@ /cdly/shell]# echo $list
aa bb
shell中的三种括号
1、大括号"{}"
{表达式;} 在当前shell内执行,命令列表后面的逗号或换行符是必须的
2、中括号"[]"
[表达式]->可以进行条件判断;$[1+1]->可以进行数值计算
3、小括号"()"
(表达式) 在子shell内执行,子shell结束后,其中的变量赋值将不再有效
三种括号实例:
[root@ /cdly/shell]# cp random.log{,.bak} # 等价于 cp random.log random.log.bak
[root@ /cdly/shell]# echo {0..10} # 输出: 0 1 2 3 4 5 6 7 8 9 10
[root@ /cdly/shell]# echo {0..10..2} # 输出: 0 2 4 6 8 10
[root@ /cdly/shell]# echo {a..z..2} # 输出: a c e g i k m o q s u w y
[root@ /cdly/shell]# echo $[2+5]
7
[root@ /cdly/shell]# (ls)
aa bb
[root@ /cdly/shell]# (seq 5)
1
2
3
4
5
Linux文件的三种时间
1、访问时间
1、文件的数据最后被访问,系统的进程直接使用文件或者一些工具,命令,脚本等间接使用;都可能会改变这个时间戳属性
2、Access Time 最后访问时间 (简写为 atime 表示文件的访问时间;当文件内容被访问时,更新这个时间)
3、[root@ /cdly/shell]# ll -u --full-time file # 输出:(访问时间:atime)
2、修改时间
1、文件内容如果有被编辑修改,该时间属性就会发生变化;在我们的ls,stat,find工具都会用或者显示这个时间戳属性
2、Modify Time 最后修改时间 (简写为 mtime 表示文件内容的修改时间,当文件的数据内容被修改时,更新这个时间)
3、[root@ /cdly/shell]# ll --full-time file # 输出:(修改时间:mtime)
3、改变时间
1、这个文件的改变时间,是指文件的状态信息(元数据,metadata),像我们平常的文件的权限,从属关系,链接数等的变化都会影响这个属性戳属性,所以,编辑文件内容涉及文件元数据的变化,所以mtime变化,ctime一定会变化
2、Change Time 最后更改时间 (简写为 ctime 表示文件的状态时间,当文件的状态被修改时,更新这个时间,例如文件的链接数、属主、属组、大小、权限、Blocks数)
3、[root@ /cdly/shell]# ll -c --full-time file # 输出:(更改时间:ctime)
# 补充
1、当读取文件时"atime"时间改变,而"mtime"、"ctime"时间不会改变
2、当修改文件时"atime"、"mtime"、"ctime"都会跟着改变
3、当修改属性时"ctime"时间改变,而"atime"、"mtime"时间不会改变
4、more、less、cat、nl、tail、tac等命令查看文件时会改变"atime"时间;ls、stat命令显示文件时不会改变"atime"时间
5、修改时间是文件内容最后一次被修改的时间,比如: vi或sed后保存的文件
6、状态改动时间是该文件的i节点最后一次被修改的时间
7、通过chmod、chown修改文件属性,会更新"ctime"时间;touch则会更改"access"、"mtime"、"ctime"时间
8、查看文件的三个时间: ls 或 stat # ls默认输出的是文件最后一次修改时间
[root@ /cdly/awk]# ll -u --full-time file # 输出:(访问时间:atime) -rw-r--r-- 1 root root 3 2019-12-02 16:15:22.293097946 +0800 file
[root@ /cdly/awk]# ll --full-time file # 输出:(修改时间:mtime) -rw-r--r-- 1 root root 3 2019-12-02 16:15:59.892252459 +0800 file
[root@ /cdly/awk]# ll -c --full-time file # 输出:(更改时间:ctime) -rw-r--r-- 1 root root 3 2019-12-02 16:15:59.892252459 +0800 file
# 查看文件内容时,文件的访问时间(Access)被修改
[root@ /cdly/awk]# cat file
[root@ /cdly/awk]# stat file
File: "file"
Size: 0 Blocks: 0 IO Block: 4096 普通空文件
Device: fd00h/64768d Inode: 131255 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2021-04-29 11:11:47.794546553 +0800
Modify: 2017-10-18 15:36:13.102395981 +0800
Change: 2017-10-18 15:36:13.102395981 +0800
# 文件内容发生改变时,文件的修改时间(Modify)被修改,此时因为文件内容被改变,故文件大小也会变化,因此文件的(Change)更改时间也被修改
[root@ /cdly/awk]# echo 11 > file
[root@ /cdly/awk]# stat file
File: "file"
Size: 3 Blocks: 8 IO Block: 4096 普通文件
Device: fd00h/64768d Inode: 131255 Links: 1
Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2021-04-29 11:11:47.794546553 +0800
Modify: 2021-04-29 11:11:59.034586808 +0800
Change: 2021-04-29 11:11:59.034586808 +0800
# 文件权限发生改变时,文件的更改时间(Change)被修改
[root@ /cdly/awk]# chmod 777 file
[root@ /cdly/awk]# stat file
File: "file"
Size: 3 Blocks: 8 IO Block: 4096 普通文件
Device: fd00h/64768d Inode: 131255 Links: 1
Access: (0777/-rwxrwxrwx) Uid: ( 0/ root) Gid: ( 0/ root)
Access: 2021-04-29 11:11:47.794546553 +0800
Modify: 2021-04-29 11:11:59.034586808 +0800
Change: 2021-04-29 11:12:09.962641503 +0800
shell的重定向及管道
1、标准输入"stdin"
代码为 0 使用 < 或 '<<' /dev/stdin -> /proc/self/fd/0
2、标准输出"stdout"
代码为 1 使用 > 或 >> /dev/stdout -> /proc/self/fd/1
3、标准错误输出"stderr"
代码为 2 使用 2> 或 2>> /dev/stderr -> /proc/self/fd/2
4、管道"|"
将左边的输出结果当做右边的输入进行处理(一个管道相当于开启一个子shell)(默认情况下错误输出是无法通过管道传递)
注意:标准输出及标准错误输出的优先级高于标准输入
> -- 表示输出到指定文件,输出之前会清空该文件
>> -- 表示标准追加重定向输出,直接将结果输出到指定文件末尾
2>&1 -- 表示将标准错误输出的结果重定向到标准输入
>file -- 直接将文件file进行清空处理
2>&1 或 |& -- 强制把标准错误输出到重定向 (可使用管道传递 )
1>&2 -- 强制把标准输出重定向错误输出 (不可使用管道传递)
&> 或 >& -- 强制将标准输出和标准错误输出重定向到同一个文件内(&>>追加的形式输出,等价: >>file 2>&1) (不可使用管道传递)
>| -- 强制覆盖标注输出(set -o noclobber无法覆盖文件,此时使用">|"可以强制覆盖)
<> -- 以读写的方式打开文件,如果文件不存在则创建,在shell中"[n]<>"省略"n"默认的fd是0 (一般除了用来打印文件内容外,无其他用处,等价"<")
权限说明
权限 | 描述 |
r[4] | 读 文件:查看文件内容 目录:查看目录下的文件与目录名称 |
w[2] | 写 文件:修改文件内容 目录:在目录下增、删、改文件与目录名称 |
x[1] | 执行 文件:可以执行文件 目录:可以用"cd"命令进入该目录 |
u | 表示属主 |
g | 表示属组 |
o | 表示其他用户 |
a | 表示所有人 |
suid | 所有用户具有属主用户的权限 |
guid | 所有用户具有属组用户的权限 |
sticky | 只能设置目录上,设置之后任何用户都可以在该目录中创建或修改文件,但是只有文件的创建者和root可以删除自己的文件 |
shell数组
1、数组的作用
注意: 一维数组最多支持1024个元素,下标范围0~1023
作用:数组也算是变量,传统的变量只能存储一个值,但数组可以存储多个值
2、数组的分类
普通数组: 只能使用整数作为数组索引 例如: arr=(1 2)、arr=("aa" "bb")、arr=('aa' 'bb') 访问: echo ${arr[0]}
关联数组: (map)可以使用字符串作为数组索引 例如: declare -A arr=([aa]=1 [bb]=2) 访问: echo ${arr[aa]}
3、数组函数调用
描述:数组定义之后在函数内是无法直接使用,需要进行导出全局才能使函数内部调用
# 方法
数组导出全局 export read_arr=$(declare -p 数组名)
函数内调用 eval $read_arr
4、数组操作方式
获取数组的长度 ${#arr[*]} 、 ${#arr[@]}
获取数组的下标 ${!arr[*]} 、 ${!arr[@]}
获取数组的下标值 ${arr[下标]}
赋值操作 arr[下标]=值
删除操作 unset arr[下标] 、unset arr
分片访问 ${arr[@]:开始下标:截取的位数}
数组替换 ${arr[@]/old/new}
5、实例
使用eval进行赋值,如:list='["a1"]="1" ["a2"]="2" ["a3"]="3"';eval "declare -A map=($list)"
vim工作模式
1、命令模式
命令模式(普通模式) : 控制光标移动,可对文本进行删除、复制、等大量的快捷键操作 (保存并退出 "ZZ")
2、输入模式
输入模式(插入模式) : 文本的基本编辑功能 (a、i、o、O ......)
3、末行模式
末行模式(编辑模式) : 保存、粘贴、退出及设置编辑环境 (保存并退出 :x、:wq、:X->需要输入密码)
使用技巧
命令 | 描述 |
dd | 删除光标所在的整行 |
ndd | 删除光标处开始的n行(n表示整数) |
yy | 复制光标所在整行 |
nyy | 复制从光标处开始的n行(n表示整数) |
p | 将之前删除(dd)或复制(yy)过的数据粘贴到光标后 |
xp | 交换两个字符位置 |
ddp | 上下两行调换 |
:g/^/m0 | 把文件内容反转,类似tac |
J | 当前行及下一行进行合并 |
dG、:%d | 删除所有行 |
d$ | 从当前位置删除到行尾 |
y$ | 从当前位置复制到行尾 |
:ab 标签 内容 | 当定义时在文本内输入"标签"按回车就会使用"内容"进行替换 |
shift+^ | 跳到本行行首 |
shift+$ | 跳到本行行尾 |
type 类型
类型 | 描述 |
alias | 别名 |
function | shell函数 |
builtin | shell内部命令 |
file | 磁盘文件 |
keyword | shell保留字 |
shell的运算符
1、比较运算符
用于整数比较、字符串比较
整数比较 | 字符串比较(单中括号用法[...]) | 字符串比较(双中括号用法[[...]]) | 解释说明 |
-eq | = 、== | = 、== | 等于 |
-ne | != | != | 不等于 |
-gt | \> 、">" | > | 大于(字符串用于ASCII比较) |
-ge | >= | 大于等于 | |
-lt | \< 、"<" | < | 小于 |
-le | <= | 小于等于 | |
-z | -z | 字符串为空(字符串长度为0) | |
-n | -n | 字符串不为空(字符串长度不为0) |
# 注意:
1、字符串比较是用于"ASCII比较",从左向右一个字符一个字符比较
2、如果在双中括号[[...]]中使用的话,就不需要使用转义符"\"转义
3、算术比较使用双括号((...))结构,例如: (( 10 > 5 ))、(( 3 != 5 )) )
4、-n 判断时建议使用双引号,否则会有bug;[ -n $a ]无论a是否有值,此次判断永远为真,因此需要使用双引号[ -n "$a" ]
5、[[...]]可以进行算术扩展,[...]不可以,例如: [[ 1+0 -eq 1 ]] && echo true || echo false --> 输出:true、[ 1+0 -eq 1 ] && echo true --> 语法错误
6、使用内容匹配判断时,如果不是完整内容判断不要使用双引号引用,特别是正则匹配"=~"
[root@ /cdly/shell]# [[ cdly = cdly ]] && echo true || echo false # 输出:true
[root@ /cdly/shell]# [[ cdly = "cdly" ]] && echo true || echo false # 输出:true
[root@ /cdly/shell]# [[ cdly =~ cdly ]] && echo true || echo false # 输出:true
[root@ /cdly/shell]# [[ cdly =~ "cdly" ]] && echo true || echo false # 输出:true
[root@ /cdly/shell]# [[ cdly = c*y ]] && echo true || echo false # 输出:true
[root@ /cdly/shell]# [[ cdly = "c*y" ]] && echo true || echo false # 输出:false
[root@ /cdly/shell]# [[ cdly =~ c*y ]] && echo true || echo false # 输出:true
[root@ /cdly/shell]# [[ cdly =~ "c*y" ]] && echo true || echo false # 输出:false
[root@ /cdly/shell]# [[ cdly = c..y ]] && echo true || echo false # 输出:false
[root@ /cdly/shell]# [[ cdly = "c..y" ]] && echo true || echo false # 输出:false
[root@ /cdly/shell]# [[ cdly =~ c..y ]] && echo true || echo false # 输出:true
[root@ /cdly/shell]# [[ cdly =~ "c..y" ]] && echo true || echo false # 输出:false
[root@ /cdly/shell]# [[ cdly = c??y ]] && echo true || echo false # 输出:true
[root@ /cdly/shell]# [[ cdly = "c??y" ]] && echo true || echo false # 输出:false
[root@ /cdly/shell]# [[ cdly =~ c??y ]] && echo true || echo false # 输出:true
[root@ /cdly/shell]# [[ cdly =~ "c??y" ]] && echo true || echo false # 输出:false
2、字符串运算符
用于字符串比较,建议使用双引号把字符串或者变量括起来
运算符 | 解释说明 |
= | 检测两个字符串是否相等,相等返回true |
!= | 检测两个字符串是否相等,不相等返回true |
-z | 检测字符串长度是否为0,为0返回true |
-n | 检测字符串长度是否为0,不为0返回true |
str | 检测字符串是否为空,不为空返回true |
[root@ /cdly/shell]# a=cdly;b=cdLy
[root@ /cdly/shell]# [ "$a" = "$b" ] && echo true || echo false # 输出:false
[root@ /cdly/shell]# [ "$a" != "$b" ] && echo true || echo false # 输出:true
[root@ /cdly/shell]# [ -z "$a" ] && echo true || echo false # 输出:false
[root@ /cdly/shell]# [ -n "$a" ] && echo true || echo false # 输出:true
[root@ /cdly/shell]# [ "$a" ] && echo true || echo false # 输出:true
3、文件操作运算符
用于文件测试,帮助文档:man test
操作 | 解释说明 |
-a | 如果文件存在则为真 |
-b | 文件是一个块设备 |
-c | 文件是一个字符设备 |
-d | (常用)判断目录是否存在 |
-e | (常用)判断文件是否存在 |
-f | (常用)判断普通文件是否存在 |
-h | 文件是一个符号链接 |
-L | 文件是一个符号链接 |
-p | 文件是一个管道 |
-S | 文件是一个套接字"socket" |
-t | 如果"文件描述符"已打开并且指向终端则为真 |
-s | (常用)文件大小不为0 |
-r | (常用)文件具有读权限 |
-w | (常用)文件具有写权限 |
-x | (常用)文件具有执行权限 |
-g | 设置了sgid标记(set-group-ID) |
-u | 设置了suid标记(set-user-ID) |
-k | 设置了"粘贴位"(sticky) |
-N | 从这个文件最后一次被读取之后,它被修改过 |
-O | 被其有效用户号所拥有则为真 |
-G | 文件的组id与你所属的组相同 |
F1 -nt F2 | 文件F1比文件F2新(根据修改时间比较) |
F1 -ot F2 | 文件F1比文件F2旧(根据修改时间比较) |
F1 -ef F2 | 文件F1和文件F2都是同一个文件的硬链接 |
! | "非" (反转上边的测试结果) |
* | 二元操作符 |
4、逻辑运算符
运算符 | 解释说明 |
逻辑与 &&、-a | str1 -a str2 、str1 && str2 第一个条件为假时,第二个条件不用再判断,最终结果为假; 第一个条件为真时,第二个条件为真则结果为真,否则为假 |
逻辑或 ||、-o | str1 -o str2 、str1 || str2 第一个条件为真时,第二个条件不用再判断,最终结果为真; 第一个条件为假时,第二个条件为真则结果为真,否则为假 |
逻辑非 ! | ! str 条件为真在取反,结果为假,否则条件为假取反则结果为真 |
5、算术运算符
注意:shell默认只支持整数计算,也就是所有可能产生的小数的运算都会舍去小数部分,可以使用:let、expr等等计算带小数
运算符 | 解释说明 |
加+ 、减- 、乘* 、除/ 、余% 、幂** | 常规算术运算符 |
加等+=、减等-=、乘等*=、除等/=、余等%= | 复合算术运算符 |
$[] 、$(()) 、expr 、bc 、declare | 其他算术运算符 |
# shell中算术运算符简单计算 (注意:以下默认情况下(bc除外)都不支持小数点运算)
let num=num+1 --> 让变量num进行加一(num=1;let num=num+1;echo $num 输出2)
echo $[1+2] --> (算术表达式)直接输出结果
echo $((1+2)) --> (算术表达式)直接输出结果(经常使用-内置命令速度最快) 另一个功能:三目运算(echo $((1>0?1:2))如果条件为真返回1,否则返回0
expr 1 + 2 --> (+ - \* /)
echo 1+2+3|bc --> 直接输出结果,需要bc计算器的支持(高精度计算语言)
declare -i a;a=1+1 --> 先定义整数变量a,然后在进行赋值,赋值后shell会自动将后面的字符串解析成算术运算
6、位运算符
1、普通shell脚本中极少使用,简单了解即可
2、右移结果最后取整,舍弃小说点后面所有值
运算符 | 解释说明 |
<< | 左移1位 (每次左移都将乘2) |
<<= | 左移几位 (=是一个数字) |
>> | 右移1位 (每次右移都将除2) |
>>= | 右移几位 (=是一个数字) |
& | 按位与 (将整数换算成二进制,相同位置比较,只有对应的二进制值都是1时结果才为1) |
| | 按位或 (将整数换算成二进制,相同位置比较,只要对应的位置有1时结果才为1) |
~ | 按位非 (快捷计算公式 ~a 值是 -(a+1),例如: echo $((~6)) 输出: -7) |
^ | 按位异或 (将整数换算成二进制,相同位置比较,只有对应的位置同为0或同为1时结果才为0,否则为1) |
! | 按位否 |
&= | 按位与赋值 |
|= | 按位或赋值 |
^= | 异或赋值 |
[root@ /cdly/shell]# echo $((5<<1)) # 5*2 输出: 10
[root@ /cdly/shell]# echo $((5<<2)) # 5*2*2 输出: 20
[root@ /cdly/shell]# echo $((5>>1)) # 5/2 输出: 2
[root@ /cdly/shell]# echo $((10>>2)) $((10>>3)) # 10/2/2 10/2/2/2 输出: 2 1
# 使用 按位异或 交换变量a和b的结果
[root@ /cdly/shell]# a=8;b=3;a=$((a^b));echo $a # 输出:11
[root@ /cdly/shell]# b=$((b^a));echo $b # 输出:8
[root@ /cdly/shell]# a=$((a^b));echo $a # 输出:3
7、自增自减运算符
运算符 | 描述 | 解释说明 |
++a | 前置自增 | 先将变量a进行自增1,然后在继续其他操作 |
--a | 前置自减 | 先将变量a进行自减1,然后在继续其他操作 |
a++ | 后置自增 | 先进行其他操作,最后在将变量a进行自增1 |
a-- | 后置自减 | 先进行其他操作,最后在将变量a进行自减1 |