Linux shell基础知识(上)
一、shell介绍
- shell是一个命令解释器,提供用户和机器之间的交互;
- 支持特定语法,比如逻辑判断、循环
- 每个用户都可以有自己特定的shell
- CentOS7默认shell为bash(Bourne Agin Shell),为了纪念这个人;
- 其他shell有:zsh、ksh等
注意:这里着重讲解bash
二、命令历史
- 查看之前使用的命令:history
[root@ying01 ~]# history |head -n3;history |tail -n3 //查看之前的命令,前3行 和后行
12 tail -n3 /etc/passwd
13 tail -n 3 /etc/group
14 useradd -u 1004 -g grp2 user4
1009 history head -n3 |tail -n3
1010 history |head -n3;tail -n3
1011 history |head -n3;history |tail -n3 //1011-11=1000说明能查看1000条命令
- bash_history 最大1000条;用下面这个命令也可以查出;
[root@ying01 ~]# echo $HISTSIZE
1000
- 内存中的命令清空:history -c
[root@ying01 ~]# history -c
[root@ying01 ~]# history
14 history
- 在Linux中,每个用户目录下都有一个.bash_history文件用于保存历史命令
[root@ying01 ~]# ls -a / //.bash_history 为隐藏文件,需要用-a选项查看
. .bash_history boot dev home lib64 mnt proc run srv tmp var
.. bin data etc lib media opt root sbin sys usr
- 查看history配置文件,并未被清空:cat .bash_history
[root@ying01 ~]# cat -n .bash_history|head -3;cat -n .bash_history|tail -3 //查看.bash_history文件前三行和后3行
1 df -m
2 df -h /etc
3 df -h /etc/
998 cd /usr/local/src
999 cd
1000 history
- 编辑 vi /etc/profile,可以看到46行默认为1000行
45 HOSTNAME=`/usr/bin/hostname 2>/dev/null`
46 HISTSIZE=1000 //这里的1000,就是history容量
47 if [ "$HISTCONTROL" = "ignorespace" ] ; then
48 export HISTCONTROL=ignoreboth
49 else
50 export HISTCONTROL=ignoredups
- 把其改为5000行
45 HOSTNAME=`/usr/bin/hostname 2>/dev/null`
46 HISTSIZE=5000 //把history容量由1000改为5000
47 if [ "$HISTCONTROL" = "ignorespace" ] ; then
48 export HISTCONTROL=ignoreboth
49 else
50 export HISTCONTROL=ignoredups
- /etc/profile修改完成;保存退出,必须用source命令才能完成更新;
[root@ying01 ~]# source /etc/profile
[root@ying01 ~]# echo $HISTSIZE
5000 //更新后,容量为5000
- 改变环境变量HISTIMEFORMAT的定义,从而改变history的格式
[root@ying01 ~]# HISTTIMEFORMAT="%Y/%m/%d %H:%M:%S "
[root@ying01 ~]# echo $HISTTIMEFORMAT
%Y/%m/%d %H:%M:%S
[root@ying01 ~]# history |tail -5
34 2018/05/30 22:46:13 echo $HISTSIZE
35 2018/05/30 22:48:02 HISTTIMEFORMAT="%Y/%m/%d %H:%M:%S "
36 2018/05/30 22:48:17 echo $HISTTIMEFORMAT
37 2018/05/30 22:49:09 history
38 2018/05/30 22:50:14 history |tail -5
- 但是这样设置,再开终端,其不能生效;因此再进入/etc/profile,把这个命令:HISTTIMEFORMAT="%Y/%m/%d %H:%M:%S " 添加到如下代码;
45 HOSTNAME=`/usr/bin/hostname 2>/dev/null`
46 HISTSIZE=5000
47 HISTTIMEFORMAT="%Y/%m/%d %H:%M:%S " //增加其格式
48 if [ "$HISTCONTROL" = "ignorespace" ] ; then
49 export HISTCONTROL=ignoreboth
50 else
51 export HISTCONTROL=ignoredups
- 永久保存,增加+a权限,只可以追加;
[root@ying01 ~]# chattr +a ~/.bash_history
注意:非正常关机退出,命令保存的不全
- !! 表示执行上一条命令
[root@ying01 ~]# !!
chattr +a ~/.bash_history
- !n 表示执行命令历史中的第几条指令
[root@ying01 ~]# history |tail -5
37 2018/05/30 22:49:09 history
38 2018/05/30 22:50:14 history |tail -5
39 2018/05/30 22:54:17 vi /etc/profile
40 2018/05/30 23:00:29 chattr +a ~/.bash_history
41 2018/05/30 23:03:17 history |tail -5
[root@ying01 ~]# !39
vi /etc/profile
- !word 表示执行命令历史中最近一次以word开头的命令
[root@ying01 ~]# !echo
echo $HISTTIMEFORMAT
%Y/%m/%d %H:%M:%S
三、命令补全及别名
- tab键,敲一下,补全指令 敲两下,系统会把所有的命令文件名列出来
[root@ying01 ~]# ls .bash_
.bash_history .bash_logout
.bash_history.bak.txt.txt.txt.bak .bash_profile
- 参数补全,安装bash-completion,
[root@ying01 ~]# yum install -y bash-completion
- 安装完之后,务必重启,init 6
[root@ying01 ~]# systemctl res //此时可以按tap,会自动列出要执行的命令
rescue reset-failed restart
[root@ying01 ~]# systemctl restart network.service
- alias别名给命令重新起个名字:alias [别名]='命令' 注意:单引号
[root@ying01 ~]# alias restartnet='systemctl restart network.service'
[root@ying01 ~]# rest
restartnet restorecon
[root@ying01 ~]# restartnet
- 查看各用户下的别名,直接用命令:alias
[root@ying01 ~]# alias
alias cp='cp -i'
alias egrep='egrep --color=auto'
alias fgrep='fgrep --color=auto'
alias grep='grep --color=auto'
alias l.='ls -d .* --color=auto'
alias ll='ls -l --color=auto'
alias ls='ls --color=auto'
alias mv='mv -i'
alias restartnet='systemctl restart network.service' //刚建立的restartnet别名,也可以查到;
alias rm='rm -i'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
- 取消别名:unalias [别名]
[root@ying01 ~]# unalias restartnet
[root@ying01 ~]# restartnet //取消后,这个别名系统找不到
-bash: restartnet: 未找到命令
- alias别名存在 .bashrc
[root@ying01 ~]# vi .bashrc
- 打开后,可以看到有3条别名配置
# .bashrc
# User specific aliases and functions
alias rm='rm -i'
alias cp='cp -i'
alias mv='mv -i'
...
...
- 其他的别名都在这些配置文件里面;
[root@ying01 ~]# cd /etc/profile.d/
[root@ying01 profile.d]# ls
256term.csh bash_completion.sh colorgrep.sh colorls.sh lang.sh less.sh vim.sh which2.sh
256term.sh colorgrep.csh colorls.csh lang.csh less.csh vim.csh which2.csh
- 比如colorls.csh这个配置文件
[root@ying01 profile.d]# vi colorls.csh
- 里面ls有配置的别名;这里其他就不用一一查看;
alias ll 'ls -l'
alias l. 'ls -d .*'
四、通配符
4.1 星号*
- 可以使用*来匹配零个或者多个字符;
[root@ying01 ~]# ls
10 11 222 5 8 anaconda-ks.cfg shiyan x.txt.gz
100 1ceshi.txt 3 6 9 NBA x.txt.bz2 y.txt.xz
[root@ying01 ~]# ls *txt
1ceshi.txt
[root@ying01 ~]# ls *txt*
1ceshi.txt x.txt.bz2 x.txt.gz y.txt.xz
- 用?号,可以匹配任何一个字符(只是一个)
[root@ying01 11]# ls
110.txt 111 112.txt 7.txt
[root@ying01 11]# ls ?.txt
7.txt
[root@ying01 11]# ls 11?.txt
110.txt 112.txt
[root@ying01 11]# ls *txt //*和?的鲜明对比
110.txt 112.txt 7.txt
- 方括号的用法:[] ,从先试验得出[]的这种用法,只是支持单位数0~9;
[root@ying01 11]# ls
10.txt 111 12.txt 3.txt 5.txt 8.txt a.txt b.txt S.txt
110.txt 112.txt 2.txt 4.txt 7.txt 9.txt A.txt C.txt w.txt
[root@ying01 11]# ls [0-9].txt //查看0-9.txt的文件
2.txt 3.txt 4.txt 5.txt 7.txt 8.txt 9.txt
[root@ying01 11]# ls [02589].txt //查看指定的文件
2.txt 5.txt 8.txt 9.txt
[root@ying01 11]# ls [5-9].txt //指定任一个范围
5.txt 7.txt 8.txt 9.txt
[root@ying01 11]# ls [0-10].txt //无法超过10,只能0-9
ls: 无法访问[0-10].txt: 没有那个文件或目录
[root@ying01 11]# ls[910].txt //无法识别指定的数
-bash: ls[910].txt: 未找到命令
[root@ying01 11]# ls [110-112].txt //再次证明无法识别非个位数
2.txt
[root@ying01 11]# ls [110112].txt
2.txt
[root@ying01 11]# ls 11[02].txt //只是匹配个位数,成功
110.txt 112.txt
[root@ying01 11]# ls [a-z].txt //也可以按字母顺序
a.txt A.txt b.txt C.txt S.txt w.txt
[root@ying01 11]# ls [abw].txt
a.txt b.txt w.txt
- 大括号的{}的用法,表示集合,或的意思;用逗号隔开
[root@ying01 11]# ls {3,5,7,8}.txt
3.txt 5.txt 7.txt 8.txt
五、输入/输出重定向
重定向命令列表如下
命令 | 说明 |
---|---|
command > file | 将输出重定向到 file。 |
command < file | 将输入重定向到 file。 |
command >> file | 将输出以追加的方式重定向到 file。 |
n > file | 将文件描述符为 n 的文件重定向到 file。 |
n >> file | 将文件描述符为 n 的文件以追加的方式重定向到 file。 |
n >& m | 将输出文件 m 和 n 合并。 |
n <& m | 将输入文件 m 和 n 合并。 |
<< tag | 将开始标记 tag 和结束标记 tag 之间的内容作为输入。 |
- command1 > file1 上面这个命令执行command1然后将输出的内容存入file1。
[root@ying01 ~]# cat 123.txt
1111111111111
2222222222222
[root@ying01 ~]# ls -ld
dr-xr-x---. 15 root root 4096 5月 31 20:31 .
[root@ying01 ~]# ls -ld > 123.txt //大于号之前的命令结果已经替换原来的内容;
[root@ying01 ~]# cat 123.txt
dr-xr-x---. 15 root root 4096 5月 31 20:31 .
- command >> file 追加内容到指定文件
[root@ying01 ~]# head -3 /etc/passwd >> 123.txt //追加passwd文件前3行,到123.txt
[root@ying01 ~]# cat 123.txt
dr-xr-x---. 15 root root 4096 5月 31 20:47 .
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
- command1 < file1 和输出重定向一样,Unix 命令也可以从文件获取输入
[root@ying01 ~]# wc -l 234.txt //查看文件多少行
2 234.txt
[root@ying01 ~]# wc -l < 234.txt //从234.txt获取其行数
2
- command1 < infile > outfile 同时替换输入和输出,执行command1,从文件infile读取内容,然后将输出写入到outfile中
[root@ying01 ~]# wc -l /etc/passwd //查看passwd文件有多少行
35 /etc/passwd
[root@ying01 ~]# wc -l < /etc/passwd > xx.txt //从passwd获取其行数,然后把结果写入到xx.txt文件中
[root@ying01 ~]# cat xx.txt
35
六、管道符、作业控制
6.1 管道符|
管道符|,将前一个指令的输出作为后一个指令的输入;
[root@ying01 ~]# cat /etc/passwd|wc -l
35
[root@ying01 ~]# cat /etc/passwd|head -3
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
6.2作业控制
在大多数情况下,用户在同一时间只运行一个作业,即它们最后向shell键入的命令。但是使用作业控制,用户可以同时运行多个作业,并在需要时在这些作业间进行切换。就如同windows一样,多任务进行;
命令 | 说明 |
---|---|
& | 直接将命令放到后台“执行” |
[crtl]+Z | 将“当前”作业放到后台“暂停” |
jobs | 观察当前后台作业状态 |
fg | 将后台作业拿到前台处理 |
bg | 作业在后台运行 |
kill | 管理后台作业 |
- 直接将命令放到后台“执行” &
[root@ying01 ~]# tar -zcf sy.tar.gz 9 & //在后台打包压缩目录9
[1] 3593 //[1]位工作序号,3593是PID
[root@ying01 ~]# vi 234.txt //可以继续工作
[1] 完成 tar -zcf sy.tar.gz 9 //因为压缩文件较小,所以此时显示后台任务显示完成
- 将“当前”作业放到后台“暂停”:[crtl]+Z
[root@ying01 ~]# vi 234.txt //执行命令 在编辑页面按[crtl]+Z
[1] 完成 tar -zcf sy.tar.gz 9
[2]+ 已停止 vi 234.txt //已经切换后台
[root@ying01 ~]# jobs
[2]+ 已停止 vi 234.txt
- 观察当前后台作业状态:jobs 有以下参数
- -l:除了列出作业号之外,同时列出PID
- -r:仅列出正在后台运行的作业
- -s:仅列出正在后台暂停的作业
[root@ying01 ~]# vim 123.txt //把[2]进程停止,再运行一个命令
[3]+ 已停止 vim 123.txt //按[crtl]+Z,返回前台
[root@ying01 ~]# jobs //用jobs查看工作进程
[2]- 已停止 vi 234.txt
[3]+ 已停止 vim 123.txt
[root@ying01 ~]# jobs -l //jobs -l 显示PID
[2]- 3603 停止 vi 234.txt
[3]+ 3615 停止 vim 123.txt
一般来说,直接执行jobs即可。在上面的输出中,有(+ -)号。(+)表示默认的作业。所以说“当前我有两个作业在后台,两个作业都是暂停的,如果我仅输入fg时,那么[3]会被拿到前台处理
- 将后台作业拿到前台处理,fg
[root@ying01 ~]# fg //fg 直接把[3]切换到前台
vim 123.txt
[3]+ 已停止 vim 123.txt
[root@ying01 ~]# jobs -l
[2]- 3603 停止 vi 234.txt
[3]+ 3615 停止 vim 123.txt
[root@ying01 ~]# fg 2 //fg 2 就可以把 [2]切换到前台
vi 234.txt
[2]+ 已停止 vi 234.txt
- 作业在后台运行:bg
[root@ying01 ~]# sleep 200 //执行命令
^Z
[4]+ 已停止 sleep 200
[root@ying01 ~]# bg 4 ;jobs //进程4在后台运行
[4]+ sleep 200 &
[2]+ 已停止 vi 234.txt
[3] 已停止 vim 123.txt
[4]- 运行中 sleep 200 & //正在运行
- 管理后台作业:kill 参数 [PID] 参数有
- -l:列出当前kill能够使用的信号(注意是小写L)
- -1:重新读取一次参数的设置文件(类似reload) ---对应的信号为SIGHUP
- -2:表示与由键盘输入ctrl+c同样的动作 ---对应的信号为SIGINT
- -9:立刻强制删除一个作业 ---对应的信号为SIGKILL
- -15:以正常方式终止一项作业 ---对应的信号为SIGTERM
[root@ying01 ~]# kill -9 4 //后面为进程的PID
-bash: kill: (4) - 没有那个进程
[root@ying01 ~]# jobs -l //查看进程和PID
[2]+ 3603 停止 vi 234.txt
[3] 3615 停止 vim 123.txt
[4]- 4355 运行中 sleep 2000 &
[root@ying01 ~]# kill -9 4355 //杀死进程
[root@ying01 ~]# jobs -l
[2]+ 3603 停止 vi 234.txt
[3] 3615 停止 vim 123.txt
[4]- 4355 已杀死 sleep 2000
七、变量
概念:环境变量PATH,它是shell预设的一种变量,通常预设的变量都是大写的。 变量就是使用一个较简单的字符串来替代某些具有特殊意义的设定以及数据。
系统预设环境变量: PATH、HOME、LOGNAME
7.1环境变量的查看
- 使用echo命令查看单个环境变量
[root@ying01 ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/tmp/:/root/bin
- env列出系统预设的全部系统变量; 直接 env
[root@ying01 ~]# env |head -5 //由于篇幅有限,只列出前面5行
XDG_SESSION_ID=15
HOSTNAME=ying01
SELINUX_ROLE_REQUESTED=
TERM=xterm
SHELL=/bin/bash
- 使用set命令显示所有本地定义的Shell变量
[root@ying01 ~]# set |head -5 //由于篇幅有限,只列出前面5行
BASH=/usr/bin/bash
BASHOPTS=checkwinsize:cmdhist:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
7.2 自定义变量
自定义变量
- 规则:变量名规则可以是:字母 数字 下划线,首位不能为数字
- 变量值拥有特殊符号时需要用单引号括起来
- 变量名规则:字母、数字下划线,首位不能为数字
[root@ying01 ~]# a1=2
[root@ying01 ~]# echo $a1
2
[root@ying01 ~]# a_1=3
[root@ying01 ~]# echo $a_1
3
- 变量值有特殊符号时需要用单引号括起来
[root@ying01 ~]# a="ab$cd" //双引号会将特殊符号脱义处理
[root@ying01 ~]# echo $a
ab
- 变量的累加,这里用双引号
[root@ying01 ~]# a=1
[root@ying01 ~]# b=2
[root@ying01 ~]# echo $a$b
12
[root@ying01 ~]# c=a"$b"c
[root@ying01 ~]# echo $c
a2c
- 我们再打开一个终端,查看在哪一个终端;
[root@ying01 ~]# w
10:44:03 up 19:15, 2 users, load average: 0.00, 0.01, 0.05
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/0 192.168.112.1 10:44 3.00s 0.03s 0.03s -bash
root pts/1 192.168.112.1 07:59 3.00s 0.59s 0.01s w
[root@ying01 ~]# echo $SSH_TTY
/dev/pts/1
- 在终端1上,定义一个变量ying01
[root@ying01 ~]# ying01=linux
[root@ying01 ~]# echo $ying01
linux
- 在复制的终端2,是没有这个变量的
[root@ying01 ~]# echo $SSH_TTY
/dev/pts/0
[root@ying01 ~]# echo $ying01
[root@ying01 ~]#
- bash是shell的一个子bash,相当于在进入一个终端
[root@ying01 ~]# bash
[root@ying01 ~]# w
11:54:02 up 19:25, 2 users, load average: 0.00, 0.01, 0.05
USER TTY FROM LOGIN@ IDLE JCPU PCPU WHAT
root pts/0 192.168.112.1 11:44 3:14 0.03s 0.03s -bash
root pts/1 192.168.112.1 07:59 2.00s 0.61s 0.00s w
- 虽然还是在终端1下,但是我们用pstree,查看我们再哪里
[root@ying01 ~]# pstree
systemd─┬─NetworkManager───2*[{NetworkManager}]
├─VGAuthService
├─agetty
├─auditd───{auditd}
├─chronyd
├─crond
├─dbus-daemon───{dbus-daemon}
├─firewalld───{firewalld}
├─irqbalance
├─lvmetad
├─master─┬─pickup
│ └─qmgr
├─polkitd───5*[{polkitd}]
├─rsyslogd───2*[{rsyslogd}]
├─sshd─┬─sshd───bash───bash───bash───pstree //在这里
│ └─sshd───bash
├─systemd-journal
├─systemd-logind
├─systemd-udevd
├─tuned───4*[{tuned}]
└─vmtoolsd───{vmtoolsd}
- 此时在 echo $ying01
[root@ying01 ~]# echo $ying01 //不生效,说明此时不在之前的终端,
[root@ying01 ~]#
- 我们exit退出当前的终端,在pstree查看环境
[root@ying01 ~]# exit
exit
[root@ying01 ~]# pstree
systemd─┬─NetworkManager───2*[{NetworkManager}]
├─VGAuthService
├─agetty
├─auditd───{auditd}
├─chronyd
├─crond
├─dbus-daemon───{dbus-daemon}
├─firewalld───{firewalld}
├─irqbalance
├─lvmetad
├─master─┬─pickup
│ └─qmgr
├─polkitd───5*[{polkitd}]
├─rsyslogd───2*[{rsyslogd}]
├─sshd─┬─sshd───bash───bash───pstree //之前还有一个bash,说明退出成功
│ └─sshd───bash
├─systemd-journal
├─systemd-logind
├─systemd-udevd
├─tuned───4*[{tuned}]
└─vmtoolsd───{vmtoolsd}
- 再次 echo $ying01
[root@ying01 ~]# echo $ying01
linux //再次证明是设定变量的那个环境
- 怎么变成全局变量呢:用命令 export
export命令用于设置或显示环境变量。用法: export [-fnp][变量名称]=[变量设置值]
- -f 代表[变量名称]中为函数名称。
- -n 删除指定的变量。变量实际上并未删除,只是不会输出到后续指令的执行环境中。
- -p 列出所有的shell赋予程序的环境变量。
[root@ying01 ~]# export ying01=linux //定义为全局变量
[root@ying01 ~]# echo $ying01
linux
[root@ying01 ~]# bash //进入一个bash
[root@ying01 ~]# echo $ying01 //成功输出
linux
[root@ying01 ~]# bash //再进入一个bash
[root@ying01 ~]# echo $ying01 //成功输出
linux
- 使用unset命令来清除环境变量
[root@ying01 ~]# unset ying01
[root@ying01 ~]# echo $ying01
//无返回值
[root@ying01 ~]#