Shell基础(二)

Shell基础(二)

evobot 764 2018-04-22

本文继续介绍Shell的基础知识,涵盖管道符和作业控制的相关知识、Shell变量的相关知识以及系统环境变量配置文件的介绍。


Shell基础(二)

管道符和作业控制

  • 管道符|表示把一个文件或命令的输出内容传递给后面的命令,使用形式如cat 1.txt | wc -lcat 1.txt | grep 'aaa';
[root@evobot tmp]# cat setRps.log | grep 'queues'
eth:eth0  queues:1
total_nic_queues:1  flow_entries:4096
  • 上面的命令输出结果,就只包含管道符后面的grep筛选的内容。
  • 作业控制表示控制程序运行状态,如暂停,继续运行,使用ctrl+z可以暂停当前任务,如暂停vim任务:
[root@evobot tmp]# vi

[1]+  已停止               vi
  • 将已经暂停的任务调回前台,使用fg命令:
[root@evobot tmp]# fg
vi
  • 当有多个任务被暂停时,使用命令jobs可以查看系统已经暂停的任务,显示出的任务会有一个序号,fg指定任务编号,即可将指定编号的任务调回前台:
[root@evobot tmp]# jobs
[1]-  已停止               vi aaa
[2]+  已停止               vi bbb
[root@evobot tmp]# fg 2
vi bbb
  • 除了fg将任务调回前台,还可以使用bg命令让任务后台运行,例如vmstat 1命令,会持续输出系统状态,我们将其设置为后台运行:
[root@evobot tmp]# jobs
[1]+  已停止               vi aaa
[root@evobot tmp]# vmstat 1
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  0      0 533176 225372 1026764    0    0     1    43  100  104  2  1 97  0  0
 1  0      0 533176 225372 1026764    0    0     0     0  111  116  0  0 100  0  0
^Z
[2]+  已停止               vmstat 1
[root@evobot tmp]# jobs
[1]-  已停止               vi aaa
[2]+  已停止               vmstat 1
[root@evobot tmp]# bg 2
[2]+ vmstat 1 &
[root@evobot tmp]#  0  0      0 532648 225376 1027132    0    0     0    20  509  585  0  0 100  0  0
 0  0      0 532648 225376 1027132    0    0     0    20  112  123  0  0 99  1  0
 0  0      0 532648 225376 1027132    0    0     0     0   93  111  0  1 99  0  0
jobs
[1]+  已停止               vi aaa
[2]-  运行中               vmstat 1 &

  • 虽然vmstat 1命令在后台运行也会在前台打印,但是执行jobs命令可以看到任务状态是运行中,并且在命令的结尾有一个&符号,这表示任务在后台运行;
  • 使用fgbg命令,在不加任务编号的情况下,默认会调用最后一次暂停的任务;
  • 在命令结尾加&,可以让命令在后台运行,并且也可以使用jobs查看任务:
[root@evobot tmp]# sleep 500
^Z
[2]+  已停止               sleep 500
[root@evobot tmp]# jobs
[1]-  已停止               vi aaa
[2]+  已停止               sleep 500
[root@evobot tmp]# sleep 1000 &
[3] 13618
[root@evobot tmp]# jobs
[1]-  已停止               vi aaa
[2]+  已停止               sleep 500
[3]   运行中               sleep 1000 &
  • jobs命令只能查看当前tty的任务,另一个tty不能查看到其他tty的任务。

shell变量

查看变量

  • 如以前说过的PATH,就是系统的一个环境变量,查看系统所以的变量,可以使用env命令查看,一般系统变量以大写字符串定义:

    [root@evobot tmp]# env
    XDG_SESSION_ID=5806
    HOSTNAME=evobot
    SHELL=/bin/bash
    TERM=xterm-256color
    HISTSIZE=3000
    USER=root
    
  • set命令也可以查看变量,并且不仅列出系统变量,还会输出用户定义的变量:

    [root@evobot tmp]# set
    ABRT_DEBUG_LOG=/dev/null
    BASH=/bin/bash
    BASHOPTS=checkwinsize:cmdhist:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:login_shell:progcomp:promptvars:sourcepath
    BASH_ALIASES=()
    BASH_ARGC=()
    BASH_ARGV=()
    BASH_CMDS=()
    BASH_COMPLETION_COMPAT_DIR=/etc/bash_completion.d
    BASH_LINENO=()
    BASH_REMATCH=()
    BASH_SOURCE=()
    BASH_VERSINFO=([0]="4" [1]="2" [2]="46" [3]="2" [4]="release" [5]="x86_64-redhat-linux-gnu")
    BASH_VERSION='4.2.46(2)-release'
    

自定义变量

  • 自定义变量直接使用=复制即可,查看变量使用echo $[变量名]

    [root@evobot tmp]# myvar=abc
    [root@evobot tmp]# echo $myvar
    abc
    [root@evobot tmp]# set | grep 'myvar'
    myvar=abc
    
  • Shell自定义变量的命名规则必须由字母、数字或下划线组成,并且首位不能为数字;变量的值存在特殊符号时,值需要使用单引号括起来,单引号可以将特殊字符脱义,而双引号则不行:

    [root@evobot tmp]# 1a=111
    -bash: 1a=111: 未找到命令
    [root@evobot tmp]# a1=111
    [root@evobot tmp]# echo $a1
    111
    [root@evobot tmp]# a_2=zxcv
    [root@evobot tmp]# echo $a_2
    zxcv
    
    [root@evobot tmp]# var1=a b c
    -bash: b: 未找到命令
    [root@evobot tmp]# var1='a b c'
    [root@evobot tmp]# echo $var1
    a b c
    [root@evobot tmp]# var2="a$bc"
    [root@evobot tmp]# echo $var2
    a
    [root@evobot tmp]# var2='a$bc'
    [root@evobot tmp]# echo $var2
    a$bc
    
  • 变量之间可以进行累加,如将两个变量的值进行拼接:

    [root@evobot tmp]# var3=1
    [root@evobot tmp]# var4=2
    [root@evobot tmp]# echo $var3$var4
    12
    [root@evobot tmp]# echo "a$var4"c
    a2c
    [root@evobot tmp]# echo "a$bc"	# $后面被识别为变量bc
    a
    

全局变量

  • 使用命令w可以查看当前登录的客户端和用户,使用TTY表示,查看当前用户的TTY,可以查看变量SSH_TTY

    [lux@evobot ~]$ w
     00:38:58 up 4 days, 3 min,  2 users,  load average: 0.00, 0.01, 0.05
    USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
    lux      pts/0    118.113.33.203   23:36    1:06   0.17s  0.00s sshd: lux [priv]    
    lux      pts/1    118.113.33.203   00:38    1.00s  0.03s  0.00s w
    
    [lux@evobot ~]$ echo $SSH_TTY
    /dev/pts/1
    
  • 普通的自定义变量只能在当前bash中访问,例如在当前shell中新建bash,新的bash中就无法再访问父shell的自定义变量:

    [lux@evobot ~]$ echo $var1
    
    [lux@evobot ~]$ var1=abc
    [lux@evobot ~]$ echo $var1
    abc
    [lux@evobot ~]$ bash
    [lux@evobot ~]$ echo $var1
    
    [lux@evobot ~]$ 
    
  • 定义全局变量使用export [变量名=值],需要注意的是,全局变量只能在子shell中生效,而子shell中的全局变量无法在父shell中生效,也不会在其他的tty中生效:

    [lux@evobot ~]$ echo $SSH_TTY
    /dev/pts/2
    [lux@evobot ~]$ echo $var1
    
    [lux@evobot ~]$ 
    
    [lux@evobot ~]$ export var2=cdef
    [lux@evobot ~]$ echo $var2
    cdef
    [lux@evobot ~]$ exit
    exit
    [lux@evobot ~]$ echo $var2
    
    [lux@evobot ~]$ 
    
  • 使用unset命令可以取消变量,命令用法为unset [变量名]:

    [lux@evobot ~]$ echo $var1
    centosvar
    [lux@evobot ~]$ unset var1
    [lux@evobot ~]$ echo $var1
    
    

环境变量配置文件

  • Linux中的环境变量配置文件分为系统全局配置和用户配置,常见的配置文件有以下几个:

    • 系统层次环境变量配置文件:

      /etc/profile 用户环境变量,登录、交互才执行;

      /etc/bashrc 用户不用登录,执行shell就生效;

    • 用户层次环境变量配置文件,每个用户的家目录下都会有以下文件:

      ~/.bashrc

      ~/.bash_profile

      ~/.bash_history

      ~/bash_logout

    • 其中profile命名的文件是与登录相关的配置,bashrc命名的文件,则是与系统或用户执行命令和脚本相关的配置;

bashrc和bash_profile的区别

  • 当直接在机器login界面登陆、使用ssh登陆或者su切换用户登陆时,.bash_profile 会被调用来初始化shell环境

  • 查看~/.bash_profile的文件内容:

    # .bash_profile
    
    # Get the aliases and functions
    if [ -f ~/.bashrc ]; then
            . ~/.bashrc		# 这里的.符号与source命令作用相同,.bash_profile会自动加载~/.bashrc;
    fi
    
    # User specific environment and startup programs
    
    PATH=$PATH:$HOME/bin
    
    export PATH
    
  • 当不登陆系统而使用ssh直接在远端执行命令,.bashrc 会被调用,已经登陆系统后,每打开一个新的Terminal时,.bashrc 都会被再次调用,在~/.bashrc的文件内容中,又会自动加载/etc/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
    
  • 所以配置环境变量,最好是卸载.bashrc文件中,因为不论是登陆还是不登陆,该文件都会被调用。

其他环境变量文件

  • ~/.bash_logout文件用来定义用户退出时系统所做的操作,如用户退出时清除命令历史,那么将相关命令写入文件即可;

  • PS1变量使用来定义用户登录后的提示符格式的,如[root@evobot ~]#,这样的格式就是在PS1变量中定义的,PS1变量的定义在/etc/bashrc中:

    [root@evobot ~]# echo $PS1
    [\u@\h \W]\$
    # 这里\u表示用户名,\h表示hostname,\W表示当前目录
    
    [root@evobot ~]# cat /etc/bashrc | grep '&& PS1='
      [ "$PS1" = "\\s-\\v\\\$ " ] && PS1="[\u@\h \W]\\$ "
    
  • 如果将\W改为\w,则当前目录将显示绝对路径,其他能够更改的选项如下表格所示:

设置选项作用
\d表示日期,格式为weekday month date
\H完整的主机名
\h主机的第一个名字
\t24小时格式(HH:MM:SS)时间
\T12小时格式
\A24小时时间格式(HH:MM),不包括秒
\u当前用户名
\vBASH的版本信息
\w工作目录的绝对路径
\w当前工作目录的目录名
\#第几个命令
\$提示字符,root用户为#,普通用户为$
  • 对于PS1,不仅可以设置格式,也可以设置颜色。
  • 除了PS1之外,还有PS2变量,PS2变量用来定义进入shell下的程序提供的终端时显示的格式,默认PS2的变量值为>

简单操作记录审计

  • 在需要针对用户操作进行历史记录以便出现问题时查找责任人时,由于history命令用户能够自行删除,所以可以通过一些配置来记录用户的操作记录;

  • 首先创建所需要的目录:

    [root@evobot ~]# mkdir -p /usr/local/records/
    [root@evobot ~]# chmod 777 /usr/local/records/
    [root@evobot ~]# chmod +t /usr/local/records/
    
  • /etc/profile中添加如下的代码:

    if [ ! -d /usr/local/records/${LOGNAME} ];then
        mkdir -p /usr/local/records/${LOGNAME}
        chmod 300 /usr/local/records/${LOGNAME}
    fi
    
    export HISTORY_FILE="/usr/local/records/${LOGNAME}/bash_history"
    export PROMPT_COMMAND='{ date +"%Y-%m-%d %T ##### $(who am i |awk "{print \$1\" \"\$2\" \"\$5}") #### $(history 1 | { read x cmd; echo "$cmd";})";} >> $HISTORY_FILE'
    
  • 这样在用户登录时,会在/usr/local/records目录下创建一个与用户名同名的目录,目录下的bash_history会将用户的历史命令记录下来,其中PROMPT_COMMAND变量是在显示PS1变量之前执行的,所以这里用户每执行一次命令再显示下一个PS1之前,都会执行PROMPT_COMMAND的定义的内容;

  • 这里定义的PROMPT_COMMAND的内容就是历史记录的格式,首先输出日期和时间,然后截取用户的用户名,tty和IP地址,history 1 | { read x cmd; echo "$cmd";}表示取history命令的最后一个记录,history命令格式如下:

    [lux@evobot ~]$ history 1
      308  history 1
    
  • { read x cmd; echo "$cmd"; }则表示将history 1的输出分别赋值给xcmd,然后打印cmd变量的值;

  • 这样一个简单的用户历史命令审计系统就可以运行了,但是实际上用户仍然可以更改目录的权限,对命令历史进行更改。



# Shell