第九课 Shell基础

目录

  1. 命令历史
  2. 命令补全
  3. 命令别名
  4. 通配符
  5. 输入输出重定向
  6. 管道符
  7. 作业控制
  8. Shell 变量
  9. 环境变量配置文件

1. 命令历史(history

Linux 可以记录每个用户所使用的命令, 并记录到 ~/.bash_history 文件中
当用户以 bash 登入 Linux 主机后, 系统会主动地由 ~/.bash_history 读取命令历史
当用户注销时, 会将最近的 HISTFILESIZE 个记录写入 ~/.bash_history 文件中

1.1 相关文件及变量
  • 文件: ~/.bash_history
  • 变量: HISTFILE=/home/<user>/.bash_history or /root/.bash_history # 指定 history 文件
  • 变量: HISTFILESIZE=1000 # history 文件最大的命令记录条数
  • 变量: HISTSIZE=1000 # 当前环境最大的命令记录条数
1.2 history 命令用法
  • history #: 列出最近的 # 条命令
[root@localhost ~]# history 5
 1033  myname='Choco Lee'
 1034  echo $myname
 1035  init0
 1036  init 0
 1037  history 5
  • history -c: 清除当前内存内的全部命令记忆
[root@localhost ~]# history 5
 1029  myname='Choco Lee'
 1030  echo $myname
 1031  init0
 1032  init 0  
 1033  history 5
[root@localhost ~]# history -c ; history
[root@localhost ~]# history
   35  history                 # 不是清空了吗? 怎么新的命令是从35开始计数?
  • history -r: 将 history 文件中的命令记忆读出到当前内存中 #一般登录时会自动进行
  • history -w: 将目前的内存中的命令记忆写入 history 文件中 # 一般登出时会自动进行
1.3 命令历史相关的使用技巧
  • !<#> 执行 history 命令显示的 第 # 条命令
[root@localhost ~]# history 10
  998  echo $myname
  999  init0
 1000  init 0
 1001  env
 1002  set
 1003  history 3
 1004  history 10
 1005  echo $myname
 1006  myname='Choco Lee'
 1007  history 10
[root@localhost ~]# !998           # 执行了第998条命令, 即 echo $myname
echo $myname
Choco Lee
  • !! 执行上一条命令
[root@localhost ~]# !998
echo $myname
Choco Lee
[root@localhost ~]# !!        # 上面的命令又执行了一遍
echo $myname
Choco Lee
  • !<keywords> 执行最近的一条以< keywords> 开头的命令
[root@localhost ~]# history 5
 1014  history 5
 1015  ls /etc/
 1016  ls /
 1017  echo $myname
 1018  history 5
[root@localhost ~]# !ls         # 执行了最近的一条以 ls 开头的命令, 即 ls /
ls /
bin   dev  home  lib64  mnt  proc  run   srv  tmp          usr
boot  etc  lib   media  opt  root  sbin  sys  tmp.tar.bz2  var

2. 命令补全(『Tab』)

非常提高工作效率的东西
这东西没法上代码,自己尝试吧,谁用谁知道。

按一下:能进行 『命令』 以及 『文件名』 的补全
按两下:能够罗列出所有符合补全的可能选项


3. 命令别名(aliasunalias

命令太长?常用命令的选项太多?有些命令后果严重,想在执行前进行提醒?
—— 用命令别名啊

3.1 查看当前已经存在的命令别名:alias
[root@localhost ~]# 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 rm='rm -I'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'
3.2 设置命令别名

alias xx=xxx -x x -x x

[root@localhost ~]# alias lm='ll -a | more'
[root@localhost ~]# alias | grep lm
alias lm='ll -a | more'
3.3 命令别名的相关文件

如果在 bash 中设置命令别名,则重启后别名失效
其实只要是用户登录后所有会调用的环境配置文档中写入自定义命令别名的设置语句,都能实现 命令别名的固定

看一下 ~/.bashrc # 下列是 root 用户的 ~./bashrc 文件, 为安全起见已进行了部分别名设置, 但普通用户一般不会有这样的别名设置

[root@localhost ~]# cat .bashrc
# .bashrc

# User specific aliases and functions

alias rm='rm -I'
alias cp='cp -I'
alias mv='mv -I'

# Source global definitions
if [ -f /etc/bashrc ]; then
    . /etc/bashrc
fi
3.4 取消命令别名:unalias <别名>
[root@localhost ~]# 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 lm='ll -a | more'            # 当前 alias 中存在 lm
alias ls='ls --color=auto'
alias mv='mv -I'
alias rm='rm -I'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'


[root@localhost ~]# unalias lm ; alias    # 取消 lm 的别名后,发现别名中已没有 lm
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 rm='rm -I'alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

4. 通配符与特殊符号

  • 通配符
符号意义
*代表0-无穷个 任意字符
?代表有且只有一个字符
[ ]代表有且仅有一个字符,且为[…]中所枚举的其中一个, 如 [13579]
[-]同上,只不过是一个范围,如[ 0-9 ],[a-z]等
[^]有且仅有一个,且不是所枚举的任何字符,如:[^a-zA-Z] 代表该位不是字母
  • 特殊符号
符号内容
#批注号
\转义符号,将特殊字符或通配符还原成一般字符
|管道符
;命令衔接符,连续执行两条命令
~当前用户家目录
$取用变量符号
&工作控制,将指令变成后台工作
!逻辑非
> 、 >>数据流重定向,output
<、<<数据流重定向,input
’ ‘单引号,无法引用变量
” “双引号,可以引用变量
` `指令引用,功能同 $(command)

5. 输入输出重定向

先看看正常情况下,执行命令时,数据流的走向

数据流走向

5.1 standard output & standard error output

标准输出,即命令成功执行时,将执行结果输出至文件 or 设备
符号:> (覆盖导出) 或 >> (追加导出)

5.1.1 标准输出(覆盖): >

如果多次命令的结果导出至同一个文件, 并采用覆盖方式,那该文件将仅保留最后一次输出的结果

[root@choco-01 ~]# cat /etc/motd 


        /\              /\         |
       /  \            /  \        |
      /    \          /    \       |
                                   |


               -----               .


[root@choco-01 ~]# cat /etc/motd > aaa   #屏幕上不再显示笑脸,原本该输出至屏幕的内容,现在输出至 aaa 文件了
[root@choco-01 ~]# cat aaa


        /\              /\         |
       /  \            /  \        |
      /    \          /    \       |
                                   |


               -----               .

既然是覆盖导出,我们再导出一个数据流到 aaa 文件,然后看看 aaa 文件变成啥样了

[root@choco-01 ~]# ls / > aaa
[root@choco-01 ~]# cat aaa           # 原本的内容不见了
777
bin
boot
dev
disk-test
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
test
tmp
usr
var
YUM

5.1.2 标准输出(追加): >>

如果多次命令结果导出至同一个文件,若采用追加方式,那每次命令的结果都会追加至该文件的末尾

[root@choco-01 ~]# echo "asdfasdf" >> aaa
[root@choco-01 ~]# cat aaa
777
bin
boot
dev
disk-test
etc
home
lib
lib64
media
mnt
opt
proc
root
run
sbin
srv
sys
test
tmp
usr
var
YUM
aaa
anaconda-ks.cfg
col.man
expect-test
passwd
passwd.linux
tee.txt
asdfasdf           # 看,最后一次导出的结果,被追加至该文件的末尾了

5.1.3 标准错误输出(覆盖): 2>

[root@choco-01 ~]# ls asdfasdf 2> bbb
[root@choco-01 ~]# cat bbb
ls: 无法访问asdfasdf: 没有那个文件或目录
[root@choco-01 ~]# ls haha 2> bbb
[root@choco-01 ~]# cat bbb
ls: 无法访问haha: 没有那个文件或目录

5.1.4 标准错误输出(追加): 2>>

[root@choco-01 ~]# cat bbb
ls: 无法访问haha: 没有那个文件或目录
[root@choco-01 ~]# ls 1234567 2>> bbb
[root@choco-01 ~]# cat bbb
ls: 无法访问haha: 没有那个文件或目录
ls: 无法访问1234567: 没有那个文件或目录

5.1.5 同时进行标准输出与标准错误输出

如果同时想将正常输出与错误输出都导入到同一个文件,且按照顺序,使用 2>&1&>

<command> ><file> 2>&1 如: ls a b > report.txt 2>&1

[root@choco-01 ~]# ls
aaa  anaconda-ks.cfg  bbb  expect-test
[root@choco-01 ~]# ls aaa asdfasdf > aaa        
ls: 无法访问asdfasdf: 没有那个文件或目录    # 屏幕上显示了标准错误输出的信息
[root@choco-01 ~]# cat aaa
aaa                                            # 文件中仅能看到标准输出的信息
[root@choco-01 ~]# ls aaa asdfasdf 2> bbb
aaa                # 屏幕上显示了标准输出的信息
[root@choco-01 ~]# cat bbb
ls: 无法访问asdfasdf: 没有那个文件或目录        # 文件中仅能看到标准错误输出的信息
[root@choco-01 ~]# ls aaa asdfasdf > aaa 2>&1
[root@choco-01 ~]# cat aaa                           # 这样就都能看到了
ls: 无法访问asdfasdf: 没有那个文件或目录
aaa
5.2 standard input

原本需要由键盘输入的数据,改由文件内容来取代

5.2.1 标准输入(以 Ctrl + d 结束)

[root@choco-01 ~]# cat > aaa
123
456
[Ctrl + d]
[root@choco-01 ~]# cat aaa
123
456


[root@choco-01 ~]# cat aaa 
123
456
[root@choco-01 ~]# cat > aaa < .bashrc     #  .bashrc 的内容替换了屏幕输入,并被放到 aaa 文件中
[root@choco-01 ~]# cat aaa
# .bashrc

# User specific aliases and functions

alias rm='rm -I'
alias cp='cp -I'
alias mv='mv -I'

# Source global definitions
if [ -f /etc/bashrc ]; then
    . /etc/bashrc
fi

5.2.2 标准输入(以 指定字符 结束)

[root@choco-01 ~]# cat > bbb << "fuckoff"
> 123123
> 456456
> fuckoff
[root@choco-01 ~]# 
5.3 巧用垃圾桶

Linux 下有一个特殊的设备 /dev/null ,所有被写入该设备的东西都会消失,所以如果有部分信息不想输出至文件,也不想输出至屏幕,那就输出至 /dev/null 吧


6. 管道符

管道的概念与数据流重定向不同,管道只是在输出至屏幕前多加一道工序,而配合管道的这些工序,往往是字符处理软件

例子:
ls /etc/ | more # 原本要直接输出至屏幕的信息, 用 more 进行了加工

ls /etc/ | grep "bash" # 原本直接输出至屏幕的信息, 用 grep "bash" 进行了加工, 筛选出了关键字


7. 作业控制

当你希望同时执行多项耗时较长的任务时, 虽然 tty 有多个, 但是来回切换也是很麻烦的
这时可以用到 linux 下的 “工作管理”

7.1 基本概念
  • foreground: 前台, 平常执行命令的界面
  • background: 后台, 看不到的地方
  • 什么样的工作适合放到后台: 不需要与用户交互的命令
  • 放入后台的工作是无法用 Ctrl + c 来终止的
  • 后台的工作有两种状态: 暂停(stop) 和 运行中( running)
7.2 直接将命令放到后台运行(&)

直接在待执行的命令的最后加上空格和 &

[root@localhost tmp]# vim aaa &
[1] 2561

加上&后, 命令直接被甩到后台进行执行, 在执行完成后会在前台弹出提示
但是, 如果执行的命令带有 stdout 或 stderr 时(如 tar -v), 则大量信息仍然会扔到前台来, 所以此时最好用上数据流重定向(推荐 2>&1

7.3 将正在运行的命令扔到后台,且置为暂停(ctrl+z)
[root@localhost tmp]# vim bbb  # 此时按下 ctrl+z, 将正在执行的 vim 扔到后台且置为暂停
[1]-  已停止               vim aaa

[2]+  已停止               vim bbb

[root@localhost tmp]# vim ccc
                                                      # 扔后台
[3]+  已停止               vim ccc

任何正在执行的任务, 在按下 ctrl+z 后, 都会被扔到后台, 且置为”暂停”状态
代码中看到每暂停一个工作, 提示信息里就显示一个数字和一个加号, 数字表示改任务目前在后台的编号, 而加号则代表该任务是最新的一个被扔后台的任务

7.4 查看后台中的任务(jobs)
[root@localhost tmp]# jobs
[1]   已停止               vim aaa
[2]-  已停止               vim bbb
[3]+  已停止               vim ccc

加号: 最新被扔进来的
减号: 次新被扔进来的
更早被扔进来的就不带符号了

jobs 的选项:
* -l:同时列出任务的 PID
* -r: 仅列出后台中处于 “running” 的任务
* -s: 仅列出后台中处于 “stop” 的任务

[root@localhost tmp]# jobs -l
[1]   2561 停止 (tty 输出)     vim aaa
[2]-  2562 停止                  vim bbb
[3]+  2563 停止                  vim ccc
7.5 将后台工作拿回到前台来(fg)

fg <job_num>

fg #不加任务号则将带加号的拿回来

[root@localhost tmp]# jobs -l
[1]   2561 停止 (tty 输出)     vim aaa
[2]-  2562 停止                  vim bbb
[3]+  2563 停止                  vim ccc


[root@localhost tmp]# fg 1              # 拿回 1 号任务
vim aaa
                                            # 再扔回去
[1]+  已停止               vim aaa


[root@localhost tmp]# jobs
[1]+  已停止               vim aaa
[2]   已停止               vim bbb
[3]-  已停止               vim ccc

再次扔回后台的命令将带有加号, 因为 加号/减号 分别代表 最新/次新, 是个相对的概念, 所以在前后台切换的过程中会不断变化
但是 任务号 不会发生变化

7.6 将后台暂停的任务激活

bg <job_num>

bg #不加任务号则将在后台激活带加号的任务

[root@localhost tmp]# tar -zcf root.tar.gz /         # 立即按 ctrl+z, 扔到后台
tar: Removing leading `/' from member names
^Z
[4]+  已停止               tar -zcf root.tar.gz /
[root@localhost tmp]# jobs
[4]+  已停止               tar -zcf root.tar.gz /       # 当前处于后台暂停状态


[root@localhost tmp]# bg 4;jobs              # 用 bg 命令在后台激活该任务
[4]+ tar -zcf root.tar.gz / &
[4]+  运行中               tar -zcf root.tar.gz / &          # 看, 在运行了
7.7 kill 命令(简)

如果想要直接移除后台的任务怎么做?
—用 kill

7.7.1 kill 的用法
kill -<signal> %<job_num>

kill -<signal> <PID>

7.7.2 常用 signal
* -1: 重新读取参数的配置文件(类似 reload)
* -9: 立即强制删除一个任务
* -15: 已正常方式结束一个任务

7.7.3 例子

[root@localhost tmp]# jobs
[4]+  已停止               tar -zcf root.tar.gz /
[root@localhost tmp]# kill -9 %4 ; jobs                       # kill 掉4号任务
[4]+  已停止               tar -zcf root.tar.gz /
[root@localhost tmp]# jobs                                    # 有一定延时才能杀死
[4]+  已杀死               tar -zcf root.tar.gz /
[root@localhost tmp]# jobs                                    # 杀干净后没有任务了
[root@localhost tmp]#

ps-1.: kill 默认是以 PID 来进行进程杀死的, 若要杀死某个任务号, 则任务号前必须加 %
ps-1.: -9是暴力杀死, -15是温柔杀死, 两者的区别在杀死 vim 时较为明显: 若用 -9 杀死, 则会留有 .filename.swp 文件, 下次再进行 vim 时会有修复提示; 而若用 -15 杀死, 则能较好地料理后事, 不会有这种缓存文件存在.


8. Shell 变量

8.1 变量的种类
  • 环境变量
    往往以纯大写来命名, bash 的子进程中仍可使用

  • 自定义变量
    推荐使用纯小写来命名, 不经过声明, 则在 bash 的子进程中无法使用

8.2 变量的命名

由字母、数字、下划线组成,且只能以非数字开头

8.3 变量的设定

语法:变量名=变量值
注意-1:如果变量值中存在空格,需要用单引号或双引号将变量值括起来
注意-2:如果变量值中有引用其他变量,需要用双引号将变量值括起来

例一:

[root@choco-01 ~]# myname=Choco
[root@choco-01 ~]# echo $myname
Choco
[root@choco-01 ~]# myname=Choco Lee
-bash: Lee: 未找到命令
[root@choco-01 ~]# echo $myname
Choco
[root@choco-01 ~]# myname='Choco Lee'
[root@choco-01 ~]# echo $myname
Choco Lee

例二:

[root@choco-01 ~]# myadd=China
[root@choco-01 ~]# full='$myname @ $myadd'
[root@choco-01 ~]# echo $full
$myname @ $myadd                      #单引号不具有引用变量的能力
[root@choco-01 ~]# full="$myname @ $myadd"
[root@choco-01 ~]# echo $full
Choco Lee @ China
[root@choco-01 ~]# 
8.4 变量的相关命令

8.4.1echo
功能:打印变量的内容

[root@choco-01 ~]# echo $LANG
zh_CN.UTF-8

8.4.2 export
功能:将变量转换为环境变量

[root@choco-01 ~]# echo $full
Choco Lee @ China
[root@choco-01 ~]# bash
[root@choco-01 ~]# echo $full          # 进入子 shell 后, 变量失效

[root@choco-01 ~]# exit
exit

[root@choco-01 ~]# export full          # 声明该变量为环境变量
[root@choco-01 ~]# bash
[root@choco-01 ~]# echo $full           # 进入子 shell 后, 变量仍让有效 
Choco Lee @ China

8.4.3 env
功能:查看环境变量

8.4.4 declare
用法:
declare [-aixr] <var_name>
选项:
* -a:定义变量为数组
* -i:定义变量为纯数字
* -x:定义变量为环境变量
* -r:定义变量为 readonly

8.5 常用环境变量
  • HOME: 当前用户的家目录
  • HOSTNAME: 该主机的主机名
  • USER: 当前用户的用户名
  • SHELL: 当前使用的 shell 类型
  • HISTSIZE: 可存储的历史命令条数
  • MAIL: 当前用户的邮箱
  • PATH: 可执行命令的所在目录
  • LANG: 当前语系
  • PS1: 命令提示符的格式, 可玩性较高, 但工作中不常用, 可自行 man bash 查看 PS1 的设置方法
  • PS2: 输入命令时强制换行后的提示符
  • OSTYPE: 当前操作系统类型
  • MACHTYPE: 安装的机器类型
  • HOSTTYPE: 主机的位数, x86 还是 x86_64

9. 环境变量配置文件

9.1 login 与 non-login
  • login shell:取得 bash 时需要完整的登录流程。如由 tty1-tty6登录时,需要输入用户的账号和密码
    读取的文件:

    • /etc/profile :系统整体的设定,对所有用户皆生效
    • ~/.bash_profile~/.bash_login~/.profile:用户的个人设定
      但是各个文件中可能又会调用其他的文件,所以一般来说,login shell 读取的文件如下图所示:
  • non-login shell:取得 bash 接口的方法不需要重复登录的举动,如在 bash 环境下,再次执行bash命令进入子 shell 时,不需要输入账号和密码

9.2 /etc/profile (login shell)

该文件会根据用户的 UID 设定好许多环境变量以及参数

9.2.1 设定环境变量
* PATH:根据 UID 决定PATH 变量是否要包含 sbin 目录
* USER:根据 id 命令的结果,显示用户名
* LOGNAME:等于 USER
* MAIL:配置好用户的邮箱
* HOSTNAME:根据 hostname 指令,决定该变量值
* HISTSIZE:直接设定历史命令记录的条数为 1000

9.2.2 调用 /etc/profile.d/*.sh

for i in /etc/profile.d/*.sh ; do
    if [ -r "$i" ]; then
       if [ "${-#*i}" != "$-" ]; then
            . "$I"
        else
            . "$i" >/dev/null
        fi
    fi
done

/etc/profile.d/ 下的脚本,主要是进行 bash 颜色、语系、vi 的别名、which 的别名等设置

9.3 ~/.bash_profile (login shell)

根据之前流程图的描述,bash shell 读取完通用配置后,才开始进行用户个性化配置的读取。
其实用户个性化配置的文件不止 ~/.bash_profile 一个,还可能有 ~/.bahs_login 和 ~/.profile
为什么有这么多个性化配置文件呢?主要是为了给从其他种类的 shell 转来使用 bash 的用户提供便利,满足其习惯罢了。
所以我们往往只能见到 ~/.bash_profile 而已

9.3.1 三种文件的读取顺序及规律

  1. ~/.bash_profile
  2. ~/.bash_login
  3. ~/.profile

其实 bash 的 login shell 只会读取上述文件中的其中一个, 读取顺序依照上面的排序, 一旦读取到其中一个文件, 就不再继续读取其余文件

9.3.2 ~/.bash_profile 内容

[root@localhost ~]# cat .bash_profile
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then
    . ~/.bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/bin

export PATH

~/.bash_profile 调取了 ~/.bashrc 文件, 并将 ~/bin 目录加入到 PATH 变量中

9.4 ~/.bashrc (non-login shell)

当通过 non-login shell 取得 bash 后, 仅会读取 ~/.bashrc 文件

先来看看 ~/.bashrc 的内容吧

[root@localhost ~]# cat .bashrc
# .bashrc

# User specific aliases and functions

alias rm='rm -I'
alias cp='cp -I'
alias mv='mv -I'

# Source global definitions
if [ -f /etc/bashrc ]; then
    . /etc/bashrc
fi

定义了几个别名, 然后又调用了 /etc/bashrc
/etc/bashrc 会完成以下任务
* 根据不同的 UID 设置 umask 值
* 根据不同的 UID 设置 PS1 变量
* 调用 /etc/profile.d/*.sh

ps. 如果家目录下没有 .bashrc 文件, 那么你的 bash 提示符可能会变成如下样子

-bash-4.2#

但是没关系, 还记得 /etc 下有个模板目录吗? 就是 /etc/shel/. 把该目录下的 .bashrc 文件复制到家目录即可.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值