Linux基础学习笔记之——BASH

BASH

1、环境变量

1.1、环境变量的功能

1.1.1、用 env 观察环境变量与常见环境变量说明
[root@li ~]# env
XDG_SESSION_ID=1
HOSTNAME=li.erver		#主机名
SELINUX_ROLE_REQUESTED=
TERM=xterm		#终端使用的环境
SHELL=/bin/bash		#目前这个环境下,使用的 shell 是哪一个程序?
HISTSIZE=1000		#默认可记录 1000 笔
SSH_CLIENT=10.0.0.100 56519 22
SELINUX_USE_CURRENT_RANGE=
SSH_TTY=/dev/pts/0
USER=root		#使用者
LS_COLORS=rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi
...
MAIL=/var/spool/mail/root		#这个用户所使用的的 mailbox 位置
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
PWD=/root		#目前用户所使用的工作目录
LANG=zh_CN.UTF-8
SELINUX_LEVEL_REQUESTED=
HISTCONTROL=ignoredups
SHLVL=1
HOME=/root
LOGNAME=root
SSH_CONNECTION=10.0.0.100 56519 10.0.0.246 22
LESSOPEN=||/usr/bin/lesspipe.sh %s
XDG_RUNTIME_DIR=/run/user/0
_=/usr/bin/env
1.1.2、用 set 观察所有变量(包含环境变量与自定义变量)

bash 不仅仅只有环境变量,还有一些与 bash 操作接口有关的变量,以及用户自己定义的变量存在。用 set 指令可以观察这些:

[root@li ~]# set
BASH=/bin/bash		#bash 的主程序放置的路径
...
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'		#bash 的版本
COLUMNS=99		#使用的字段有几个字段长度
...
IFS=$' \t\n'		#预设的分隔符
...
PS1='[\u@\h \W]\$ '		#这个是命令提示符,可以改动的!
...
$		#目前这个 shell 所使用的 PID
?		#刚刚执行完指令的回传值,执行成功回传 0

比较重要的几个:

  • PS1(提示字符的设定):

    • \d:可显示 “星期 月 日” 的日期格式
    • \H:完整的主机名,FQDN
    • \h:仅取主机名在第一个小数点之前的名字
    • \t:显示时间,为 24 小时格式的 “HH:MM:SS”
    • \T:显示时间,为 12 小时格式的 “HH:MM:SS”
    • \A:显示时间,为 24 小时格式的 “HH:MM”
    • @:显示时间,为 12 小时格式的 “am/pm”
    • \u:目前使用者的账号
    • \v:BASH 的版本信息
    • \w:完整的工作目录
    • \W:仅列出最后一个目录名
    • \#:下达的第几个指令
    • \$:提示字符,如果是 root,提示符为 #,否则为 $
[root@li home]# PS1='[\u@\h \w \A #\#]\$ '
[root@li /home 10:51 #7]# PS1='[\u@\h \w \t #\#]\$ '
[root@li /home 10:52:28 #8]# PS1='[\u@\h \w \@ #\#]\$ '
[root@li /home 10:52 上午 #9]# PS1='[\u@\h \t \@ #\#]\$ '
[root@li 10:53:03 10:53 上午 #10]# PS1='[\u@\h \w \t #\#]\$ '
[root@li /home 10:53:31 #11]#
  • $

    目前这个 Shell 的线程编号,即 PID

[root@li /home 10:54:41 #13]# echo $$
1192
  • ?

    如果指令执行成功,则会回传一个 0 值。如果失败,回传一个非 0 值

[root@li /home 10:56:51 #14]# echo $SHELL
/bin/bash
[root@li /home 10:58:08 #15]# echo $?		#上一个指令执行成功,显示 0
0
[root@li /home 10:58:14 #16]# 12name=li
-bash: 12name=li: 未找到命令
[root@li /home 10:58:21 #17]# echo $?		#因为有问题,回传一个非 0
127
[root@li /home 10:58:24 #18]# echo $?		#因为上一个 echo $? 执行成功
0

1.2、export:自定义变量转成环境变量

自定义变量与环境变量之间的差异是什么呢?其实这两个的差异在于“该变量是否会被子程序继续引用”

当你登入 Linux 并取得一个 bash 之后,你的 bash 就是一个独立的程序,这个程序的识别使用的是一个称为程序标识符,被称为 PID。接下来你在这个 bash 底下所下达的任何指令都是由这个 bash 所衍生出来的,那些被下达的指令就被称为子程序。

子程序会继承父类的环境变量,而不会继承自定义变量。想要变量的内容在子程序中继续执行的话,请执行:

[root@li /home 10:58:24 #18]# export 变量名

当下达 export 而没有接变量时,那么就会显示出所有的环境变量:

[root@li ~]# export
declare -x HISTCONTROL="ignoredups"
declare -x HISTSIZE="1000"
declare -x HOME="/root"
declare -x HOSTNAME="li.erver"
declare -x LANG="zh_CN.UTF-8"
...

1.3、影响显示结果的语系变量(locale)

Linux 到底支持多少的语系呢?可以由 locate 查询到:

[root@li ~]# locale -a
zh_CN
zh_CN.gb18030
zh_CN.gb2312
zh_CN.gbk
zh_CN.utf8		#万国码的中文编码
...

如何修订这些编码呢?

[root@li ~]# locale
LANG=zh_CN.UTF-8				#主语言环境
LC_CTYPE="zh_CN.UTF-8"			#字符(文字)辨识的编码
LC_NUMERIC="zh_CN.UTF-8"		#数字系统的显示编码
LC_TIME="zh_CN.UTF-8"			#时间系统的显示编码
LC_COLLATE="zh_CN.UTF-8"		#字符串
LC_MONETARY="zh_CN.UTF-8"
LC_MESSAGES="zh_CN.UTF-8"
LC_PAPER="zh_CN.UTF-8"
LC_NAME="zh_CN.UTF-8"
LC_ADDRESS="zh_CN.UTF-8"
LC_TELEPHONE="zh_CN.UTF-8"
LC_MEASUREMENT="zh_CN.UTF-8"
LC_IDENTIFICATION="zh_CN.UTF-8"
LC_ALL=

可以让每个用户自己去调整自己喜欢的语系,但是整体系统默认的语系定义在哪里?其实就在 /etc/locale.conf 里。

[root@li ~]# cat /etc/locale.conf
LANG="zh_CN.UTF-8"

1.4、变量的有效范围

  • 环境变量 = 全局变量
  • 自定义变量 = 局部变量

1.5、变量的键盘读取、数组与宣告:read,array,declare

1.5.1、read
[root@li ~]# read [-pt] 变量名
选项与参数:
-p:后面接的是提示字符!
-t:后面接的是秒数,不会一直等待。
[root@li ~]# read atest
This is a test				#输入变量内容
[root@li ~]# echo $atest
This is a test
[root@li ~]# read -p "Please keyin your name" -t 30 named
Please keyin your nameLi^C
[root@li ~]# read -p "Please keyin your name:" -t 30 named
Please keyin your name:Li
[root@li ~]# echo $named
Li
1.5.2、declare/typeset

declare 或 typeset 是一样的功能,就是在“宣告变量的类型”。

[root@li ~]# declare [-aixrp] 变量名
选项与参数:
-a:将后面的变量名定义为数组类型
-i:定义为整数类型
-x:用法与 export 一样,变为环境变量
-r:设置为 readonly 类型,该变量不能被修改,也不能 unset
-p:列出变量类型
[li@li root]$ sum=100+300+50
[li@li root]$ echo $sum
100+300+50			#为什么没有计算出总和?
[li@li root]$ declare -i sum=100+300+50
[li@li root]$ echo $sum
450

如果需要非字符串类型的变量,那就要进行变量的宣告才行

#让 sum 变为环境变量
[li@li root]$ declare -x sum
[li@li root]$ export | grep sum
declare -ix sum="450"
#让 sum 变成只读变量
[li@li root]$ declare -r sum
[li@li root]$ sum=testing
bash: sum: 只读变量
#取消环境变量
[li@li root]$ declare +x sum
[li@li root]$ declare -p sum
declare -ir sum="450"
1.5.3、数组变量类型
[li@li root]$ 数组名[index]=变量内容
[li@li root]$ var[1]="small min"
[li@li root]$ var[2]="big min"
[li@li root]$ var[3]="nice min"
[li@li root]$ echo "${var[1]},${var[2]},${var[3]}"
small min,big min,nice min

1.6、与文件系统及程序的限制关系:ulimit

bash 是可以 “限制用户的某些系统资源的”,包括可以开启的文件数量,可以使用的 CPU 时间,可以使用的内存总量等。

[li@li root]$ ulimit [-SHacdfltu] [配额]
选项与参数:
-S:hard limit,严格的设定,必定不能超过这个设定的值
-H:soft limit,警告的设定,超过会有警告信息
-a:不接任何参数,可列出所有的限制额度
-c:当某些程序发生错误时,系统可能会将该程序在内存中的信息写成文件,这种文件称为核心文件。这个参数会限制文件的大小
-f:此 shell 可以建立的最大文件容量
-d:程序可以使用的最大断裂内存容量
-l:可用于锁定的内存量
-t:可使用的最大 CPU 时间
-u:单一用户可以使用的最大程序数量
#列出你目前身份的所有限制数据
[li@li root]$ ulimit -a
core file size          (blocks, -c) 0				#0 代表没有限制
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited		#可建立的单一文件大小
pending signals                 (-i) 3795
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024			#同时可开启的文件数量
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 3795
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
#限制用户仅能建立 10MBytes 以下的容量文件
[li@li root]$ ulimit -f 10240
[li@li root]$ ulimit -a | grep -e '^file size'
file size               (blocks, -f) 10240

2、命令别名与历史命令

2.1、命令别名设定:alias、unalias

目前有哪些命令别名呢?

[li@li root]$ alias
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 vi='vim'
alias which='alias | /usr/bin/which --tty-only --read-alias --show-dot --show-tilde'

设置命令别名:

[li@li root]$ alias rm='rm -i'
[li@li root]$ alias lm='ls -al | grep'

取消命令别名:

[li@li root]$ unalias lm

2.2、历史命令:history

[li@li root]$ history [n]
[li@li root]$ history [-c] 
[li@li root]$ history [-raw] histfiles
选项与参数:
n:就是数字,列出最近 n 笔命令记录
-c:将目前的 shell 中的所有 history 内容全部删除
-a:将目前新增的 history 指令新增加入 histfile 中,若没有加 histfile,则预设写入 ~/.bash_history
-r:将 histfiles 的内容读到目前这个 shell 的 history 记忆中
-w:将目前的 history 记忆中的内容写入 history
#列出目前内存中所有的 history 记录
[li@li root]$ history
    1  path=$PATH
    2  echo $path
    3  alias
    4  alias rm='rm -i'
    5  alias lm='ls -al | grep'
    6  unalias lm
    7  alias h='history'
    8  history
#列出最近 3 笔记录
[li@li root]$ history 3
    7  alias h='history'
    8  history
    9  history 3
#立刻将目前的资料写入 histfile 当中
[li@li root]$ history -w
[li@li root]$ echo $HISTSIZE
1000

那么 history 这个命令只可以让我们查询命令而已吗?当然不止!我们可以利用相关的功能来帮我们执行命令:

[li@li root]$ !number			#执行第几笔指令的意思
[li@li root]$ !command			#由最近的指令向前搜寻“指令串开头为 command”的那个指令,并执行
[li@li root]$ !!				#就是执行上一个指令
[li@li root]$ history
	...
   12  history
   13  ls /usr/local/src/python/
   14  history
[li@li root]$ !13					#执行第13条指令
ls /usr/local/src/python/
contents   hello3.py  hello.py     tsTestser02.py  tsTservSS.py
hello2.py  hello4.py  __pycache__  tsTestser.py    tsUserv.py
[li@li root]$ !!					#执行上一条指令
ls /usr/local/src/python/
contents   hello3.py  hello.py     tsTestser02.py  tsTservSS.py
hello2.py  hello4.py  __pycache__  tsTestser.py    tsUserv.py
[li@li root]$ !ls					#指令“ls”开头的指令
ls /usr/local/src/python/
contents   hello3.py  hello.py     tsTestser02.py  tsTservSS.py
hello2.py  hello4.py  __pycache__  tsTestser.py    tsUserv.py

3、Bash Shell 的操作环境

3.1、路径与指令搜寻顺序

指令的运作顺序是这样的:

  1. 以相对/绝对路径执行指令;
  2. 由 alias 找到该指令来执行;
  3. 由 bash 内建的(builtin)指令来执行;
  4. 通过 $PATH 这个变量的顺序搜寻到的第一个指令来执行。
#设定 echo 的命令别名为 echo -n,然后再观察 echo 执行的顺序
[li@li root]$ alias echo='echo -n'
[li@li root]$ type -a echo
echo 是 `echo -n' 的别名
echo 是 shell 内嵌
echo 是 /bin/echo
echo 是 /usr/bin/echo

3.2、bash 的进站与欢迎信息:/etc/issue,/etc/motd

[li@li root]$ cat /etc/issue
\S
Kernel \r on an \m

man issue 可以得到如下结果:

issue 内的各代码意义 说明
\d 本地端的时间
\l 显示第几个终端机的接口
\m 显示硬件的等级(i386/i486/…)
\n 显示主机的网路名称
\O 显示 domain name
\r 操作系统的版本(相当于 nuame -r)
\t 显示本地端时间的时间
\S 操作系统的名称
\v 操作系统的版本
#以 root 身份修改 /etc/issue 的内容
[root@li ~]# vim /etc/issue
[root@li ~]# cat /etc/issue
\S(terminal: \l)
Date: \d \t
Kernel \r on an \m
Li welcome you!

然后再 tty4 进站,可以发现:

Linux基础学习笔记之——BASH_第1张图片

除了 /etc/issue 之外,还有个 /etc/issue.net后者主要是提供给 telnet 远程登录的

#以 root 身份修改 /etc/issue.net 的内容
[root@li ~]# vim /etc/issue.net
[root@li ~]# cat /etc/issue.net
(terminal: \l)
Date: \d \t
Kernel \r on an \m
Li welcome remote user!

至于如果你想要让使用者登入后取得一些信息,例如你想要大家都知道的信息,那么可以将讯息加入 /etc/motd 里面去。例如:当登入后,告诉登入者,系统将在某个时间进行维护工作,可以这样做:

[root@li ~]# vim /etc/motd
[root@li ~]# cat /etc/motd
欢迎各位用户!
我们的系统将在每周的周五下午15时进行维护,给您带来的不便望请谅解!

那么当用户(包括所有的用户)登入主机时,就会显示:

Linux基础学习笔记之——BASH_第2张图片

3.3、bash 的环境配置文件

为什么一进入 bash 就取得了一堆有用的变量?这是因为系统有一些环境配置文件的存在,让 bash 在启动时直接读取这些配置文件,以规划好 bash 的操作环境。这些配置文件又可以分为全体系统的配置文件以及用户个人的偏好配置文件。要注意的是,前面谈到的命令别名、自定义变量,在注销 bash 后就会失效,所以要保留你的设定,就需要将这些设定写入配置文件才行

3.3.1、login 与 non-login shell
  • login shell:取得 bash 时需要完整的登入流程,就称为 login shell。
  • non-login shell:取得 bash 接口的方法不需要重复登入的举动,举例来说,(1)你以 X Window 登入 Linux 后,再以 X 的图形界面接口启动终端,此时那个终端接口并没有需要再次输入账号密码,那个 bash 的环境就称为 non-login shell;(2)你在原本的 bash 下再次下达 bash 这个指令,同样没有输入账号密码,那第二个 bash 也是 non-login shell。

两个在取得 bash 的情况中,读取的配置文件是不一样的。

login shell 需要读取的配置文件

  1. /etc/profile:这是系统整体的设定,最好不要修改;
  2. ~/.bash_profile 或 ~/.bash_login 或 ~/.profile:属于使用者个人设定;
3.3.1.1、/etc/profile(login shell 才会去读)

每个账号登入 bash 都需要去读的配置文件!这个文件的主要变量为:

  • PATH:会依据 UID 决定 PATH 变量要不要含有 sbin 的系统指令目录;
  • MAIL:依据账号名称设定好使用者的 maixbox 到 /var/spool/mail/账号名;
  • USER:根据用户的账号设定此一变量;
  • HOSTNAME:依据主机的 hostname 指令决定此一变量;
  • HISTSIZE:历史命令记录数;
  • umask:包括 root 默认的 022 而一般用户为 002 等!

/etc/profile 可不止会做这些事,它还会呼叫外部的设定数据

  • /etc/profile.d/*.sh
  • /etc/locale.conf
  • /usr/share/bash-completion/completions/*
3.3.1.2、~/bash_profile(login shell 才会读)

bash 在读完了整体的环境配置的 /etc/profile 文件后,接下来是会读取使用者个人的配置文件。在 login shell 的 bash 环境中,所读取的个人偏好文件其实主要有三个,依次为:

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

其实 bash 的 login shell 会读取上面三个文件其中的一个,而读取顺序是依照上面的顺序的。

[li@li ~]$ ll -a
总用量 16
drwx------. 2 li   li     83 8月   5 16:52 .
drwxr-xr-x. 3 root root   16 7月  31 17:12 ..
-rw-------. 1 li   li   1003 8月   5 17:35 .bash_history
-rw-r--r--. 1 li   li     18 4月   1 10:17 .bash_logout
-rw-r--r--. 1 li   li    193 4月   1 10:17 .bash_profile
-rw-r--r--. 1 li   li    231 4月   1 10:17 .bashrc
[li@li ~]$ cat .bash_profile
# .bash_profile

# Get the aliases and functions
if [ -f ~/.bashrc ]; then			#底下这三行在判断并读取 ~/.bashrc
        . ~/.bashrc
fi

# User specific environment and startup programs

PATH=$PATH:$HOME/.local/bin:$HOME/bin		#底下这几行在处理个人化

export PATH

Linux基础学习笔记之——BASH_第3张图片

从流程图可知,最终读取的文件是 ~/.bashrc 这个文件!所以,你当然可以将自己的偏好设置写入该文件即可。

3.3.1.3、source:读入环境变量文件的指令

通常设置的变量都是在注销再登录的时候才生效,那么能不能直接读取配置文件而不用注销登入呢?那就需要 source 指令:

[li@li ~]$ source 配置文件名
[li@li ~]$ source .bashrc
[li@li ~]$ . .bashrc

利用 source 或小数点(.)都可以将配置文件内容读取到目前的 shell 的环境中

3.3.2、~/.bashrc(non-login shell 才会读)

只会读取 ~/.bashrc 的内容

[root@li ~]# 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 规范出 numask 的值;
  • 依据不同的 UID 规范出提示字符(就是 PS1 的值);
  • 呼叫 /etc/profile.d/*.sh 的设定。
3.3.3、其他相关配置
  • /etc/man_db.conf
  • ~/.bash_history
  • ~/.bash_logout

4、数据流重定向

4.1、什么是数据流重定向

Linux基础学习笔记之——BASH_第4张图片

4.1.1、standard output 与 standard error output

标准输出指的是 “指令执行所回传的正确的信息”,而标准错误输出可理解为 “指令执行失败后,所传回的错误信息”。不管是正确或错误的数据都是默认输出到屏幕上,那能不能通过某种机制将这两股数据分开呢?当然可以!那就是数据流重定向的功能。

  1. 标准输入(stdin):代码为 0,使用 < 或 <<;
  2. 标准输出(stdout):代码为 1,使用 > 或 >>;
  3. 标准错误输出(stderr):代码为 2,使用 2> 或 2>>;

具体来说:

  • 1>:覆盖
  • 1>>:累加
  • 2>:覆盖
  • 2>>:累加
4.1.2、/dev/null 垃圾桶黑洞设备与特殊写法

如果错误信息出现时,想要把错误信息忽略或不显示,这个时候装备 /etc/null 就很重要了!这个 /etc/null 会吃掉任何导向这个设备的信息!

如果想将正确与错误信息通通写入同一个文件去呢?这个时候就需要特殊写法:

[root@li ~]# find /home -name .bashrc > list 2>&1
[root@li ~]# find /home -name .bashrc &> list
4.1.3、standard input:< 与 <<

<:简单来说,那就是 “将原本需要由键盘输入的数据,改由文件内容取代”

[root@li ~]# cat > catfile
testing
cat file test		#按下 [ctrl]+d 离开
[root@li ~]# cat catfile
testing
cat file test
#用某个文件的内容取代键盘输入
[root@li ~]# cat > catfile < ~/.bashrc
[root@li ~]# ll catfile ~/.bashrc
-rw-r--r--. 1 root root 176 8月   6 09:57 catfile
-rw-r--r--. 1 root root 176 8月   5 09:06 /root/.bashrc
[root@li ~]# cat catfile
# .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
#使用 cat 直接将输入的信息输出到 catfile 中,且由键盘输入 eof 时,该次输入就结束了
[root@li ~]# cat > catfile << "eof"
> This is a test
> Ok now stop
> eof
[root@li ~]# cat catfile
This is a test
Ok now stop

4.2、命令执行的判断依据:;,&&,||

指令下达情况 说明
cmd1 ; cmd2 不考虑指令的相关性的连续指令下达
cmd1 && cmd2 1.若 cmd1 执行完毕且正确执行( ? = 0 ) , 则 开 始 执 行 c m d 2 ; < b r / > 2. 若 c m d 1 执 行 完 毕 且 为 错 误 ( ?=0),则开始执行 cmd2;
2.若 cmd1 执行完毕且为错误(
?=0cmd2<br/>2.cmd1
?=1),则 cmd2 不执行。
cmd1 || cmd2 1.若 cmd1 执行完毕且正确执行( ? = 0 ) , 则 c m d 2 不 执 行 ; < b r / > 2. 若 c m d 1 执 行 完 毕 且 为 错 误 ( ?=0),则 cmd2 不执行;
2.若 cmd1 执行完毕且为错误(
?=0cmd2<br/>2.cmd1
?=1),则开始执行 cmd2。

Linux基础学习笔记之——BASH_第5张图片


5、管线命令(pipe)

Linux基础学习笔记之——BASH_第6张图片

  • 管线命令仅会处理标准输出,对于标准错误输出会给予忽略;
  • 管线命令必须要能够接收来自前一个指令的数据成为标准输入继续处理才行。

5.1、撷取命令:cut,grep

通常撷取命令是针对“一行一行”来分析的,并不是整篇分析的。

5.1.1、cut
[root@li ~]# cut -d'分隔字符' -f fields		#用于有特定分隔符
[root@li ~]# cut -c 字符区间				#用于排列整齐的讯息
#将 PATH 变量取出,找出第五个路径
[root@li ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
[root@li ~]# echo $PATH | cut -d ":" -f 5
/usr/sbin

#找出第3与第5呢?
[root@li ~]# echo $PATH | cut -d ":" -f 3,5
/sbin:/usr/sbin

#将 export 输出的信息,取得第 12 字符以后的信息
[root@li ~]# export
declare -x HISTCONTROL="ignoredups"
declare -x HISTSIZE="1000"
declare -x HOME="/root"
declare -x HOSTNAME="li.erver"
declare -x LANG="zh_CN.UTF-8"
declare -x LESSOPEN="||/usr/bin/lesspipe.sh %s"
declare -x LOGNAME="root"
...
#整齐排列的
[root@li ~]# export | cut -c 12-
HISTCONTROL="ignoredups"
HISTSIZE="1000"
HOME="/root"
HOSTNAME="li.erver"
LANG="zh_CN.UTF-8"
LESSOPEN="||/usr/bin/lesspipe.sh %s"
LOGNAME="root"
...

#用 last 将显示登入者的信息中,仅留下大名
[root@li ~]# last
root     pts/0        li-911m.lan      Thu Aug  6 08:56   still logged in
reboot   system boot  3.10.0-1127.el7. Thu Aug  6 08:55 - 10:16  (01:20)
root     tty6                          Wed Aug  5 17:37 - crash  (15:18)
root     pts/1        li-911m.lan      Wed Aug  5 17:35 - crash  (15:20)
root     pts/1        mysql.lan        Wed Aug  5 17:27 - 17:29  (00:01)
...
[root@li ~]# last | cut -d " " -f 1
root
reboot
root
root
root
...

cut 在处理很多空格相连的时候会很吃力,那就需要 awk 了!

5.1.2、grep
[root@li ~]# grep [-acinv] [--color=auto] '搜寻的字符串' 文件名
选项与参数:
-a:将 binary 文件以 text 文件的方式搜寻数据
-c:计算次数
-i:忽略大小写
-n:输出行号
-v:反向选择
#将 last 当中,有出现 root 那一行取出来
[root@li ~]# last | grep 'root'
root     pts/0        li-911m.lan      Thu Aug  6 08:56   still logged in
root     tty6                          Wed Aug  5 17:37 - crash  (15:18)
root     pts/1        li-911m.lan      Wed Aug  5 17:35 - crash  (15:20)
root     pts/1        mysql.lan        Wed Aug  5 17:27 - 17:29  (00:01)
...

#没有 root 就取出来
[root@li ~]# last | grep -v 'root'
reboot   system boot  3.10.0-1127.el7. Thu Aug  6 08:55 - 10:23  (01:27)
reboot   system boot  3.10.0-1127.el7. Wed Aug  5 15:25 - 10:23  (18:57)
reboot   system boot  3.10.0-1127.el7. Wed Aug  5 10:27 - 10:23  (23:55)
...

#只要有 root 就取出,且只取第一行
[root@li ~]# last | grep 'root' | cut -d ' ' -f 1
root
root
root
...

5.2、排序命令:sort,wc,uniq

5.2.1、sort
[root@li ~]# sort [-fbMnrtuk] [文件或标准输入]
选项与参数:
-f:忽略大小写
-b:忽略最前面的空格字符
-M:以月份的名字排序
-n:使用“纯数字”进行排序
-r:反向排序
-u:就是uniq,相同的数据,仅出现一次
-t:分隔符,预设是以[tab]分隔的
-k:以那个区间来进行排序
#个人账号都记录在 /etc/passwd 下,请将账号排序
[root@li ~]# cat /etc/passwd | sort
adm:x:3:4:adm:/var/adm:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
dbus:x:81:81:System message bus:/:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
halt:x:7:0:halt:/sbin:/sbin/halt
li:x:1000:1000:li:/home/li:/bin/bash
...

#/etc/passwd 的内容是以 : 来分隔的,想以第三栏来排序
[root@li ~]# cat /etc/passwd | sort -t ':' -k 3
root:x:0:0:root:/root:/bin/bash
li:x:1000:1000:li:/home/li:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
...
5.2.2、uniq

重复数据只显示一行:

[root@li ~]# uniq [-ic]
选项与参数:
-i:忽略大小写
-c:进行计数
#使用 last 将账号列出,仅取出账号栏,进行排序后仅取出一位
[root@li ~]# last | cut -d ' ' -f 1 | sort | uniq

reboot
root
wtmp

#想要知道每个人登录的次数
[root@li ~]# last | cut -d ' ' -f 1 | sort | uniq -c
      1
      7 reboot
     16 root
      1 wtmp
5.2.3、wc
[root@li ~]# wc [-lwm]
选项与参数:
-l:仅列出行
-w:仅列出多少字(英文单字)
-m:多少字符
[root@li ~]# cat /etc/man_db.conf | wc
    131     723    5171
#   行		字数	字符数

5.3、双重重定向:tee

Linux基础学习笔记之——BASH_第7张图片

tee 会同时将数据流分送到文件和屏幕去。

[root@li ~]# tee [-a] 文件
选项与参数:
-a:累加

5.4、字符转换命令:tr,col,join,paste,expand

5.4.1、trt

tr 用来删除一段信息中的文字,或者是进行文件信息的替换!

[root@li ~]# tr [-ds] SET1 ...
选项与参数:
-d:删除
-s:取代掉重读的字符串
#所有的小写变成大写
[root@li ~]# last | tr '[a-z]' '[A-Z]'
ROOT     PTS/0        LI-911M.LAN      THU AUG  6 08:56   STILL LOGGED IN
REBOOT   SYSTEM BOOT  3.10.0-1127.EL7. THU AUG  6 08:55 - 10:39  (01:43)
ROOT     TTY6                          WED AUG  5 17:37 - CRASH  (15:18)
ROOT     PTS/1        LI-911M.LAN      WED AUG  5 17:35 - CRASH  (15:20)
ROOT     PTS/1        MYSQL.LAN        WED AUG  5 17:27 - 17:29  (00:01)

#将 /etc/passwd 输出的信息中的 : 删除
[root@li ~]# cat /etc/passwd | tr -d ':'
rootx00root/root/bin/bash
binx11bin/bin/sbin/nologin
daemonx22daemon/sbin/sbin/nologin
admx34adm/var/adm/sbin/nologin
5.4.2、col
[root@li ~]# col [-xb]
选项与参数:
-x:将 tab 转换成对应的空格键
[root@li ~]# cat /etc/man_db.conf  | col -x | cat -A | more
5.4.3、join

join 是在处理两个文件的数据,而且,主要是在处理 “两个文件当中,有 “相同数据” 的那一行,才将它们加在一起” 的意思。

[root@li ~]# join [-til2] 文件1 文件2
选项与参数:
-t:join 默认是以空格符来分隔的,并且比对“第一个字段”的数据,如果两个文件相同,则将两笔数据联成一行,且第一个字段放在第一个!
-i:忽略大小写
-1:数字 1,代表“第一个文件要用那个字段来分析”的意思
-2:代表“第二个文件要用那个字段来分析”的意思
#用 root 身份,将 /etc/passwd 与 /etc/shadow 相关数据整合成一栏
[root@li ~]# head -n 3 /etc/passwd /etc/shadow
==> /etc/passwd <==
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

==> /etc/shadow <==
root:$6$Wut1Cw0fCGVGBkEF$H/OVyZf7Y00AQEASWVcyFvo2ZBgv4pgH3Qp5QuFH8bOZXKgxZw0CaiZ/bVW2/estLhu4hWJZW6otFsWKS/iEa1::0:99999:7:::
bin:*:18353:0:99999:7:::
daemon:*:18353:0:99999:7:::
#可以发现,这两个文件最左边都是相同账号,且以“:”分隔
[root@li ~]# join -t ':' /etc/passwd /etc/shadow | head -n 3
root:x:0:0:root:/root:/bin/bash:$6$Wut1Cw0fCGVGBkEF$H/OVyZf7Y00AQEASWVcyFvo2ZBgv4pgH3Qp5QuFH8bOZXKgxZw0CaiZ/bVW2/estLhu4hWJZW6otFsWKS/iEa1::0:99999:7:::
bin:x:1:1:bin:/bin:/sbin/nologin:*:18353:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin:*:18353:0:99999:7:::

#我们知道 /etc/passwd 第四个字段是 GID,那个 GID 记录在 /etc/group 当中的第三个字段,如何整合?
[root@li ~]# head -n 3 /etc/passwd /etc/group
==> /etc/passwd <==
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

==> /etc/group <==
root:x:0:
bin:x:1:
daemon:x:2:
[root@li ~]# join -t ':' -1 4 /etc/passwd -2 3 /etc/group | head -n 3
join: /etc/passwd:6: is not sorted: sync:x:5:0:sync:/sbin:/bin/sync
join: /etc/group:11: is not sorted: wheel:x:10:
0:root:x:0:root:/root:/bin/bash:root:x:
1:bin:x:1:bin:/bin:/sbin/nologin:bin:x:
2:daemon:x:2:daemon:/sbin:/sbin/nologin:daemon:x:
5.4.4、paste

join 需要比较两个文件的相关性,paste 就直接 “将两行贴在一起,且中间是以 [tab] 来分隔的” 。

[root@li ~]# paste [-d] 文件1 文件2
选项与参数:
-d:后面可以接分隔符
-:后面 file 如果写成 -,表示来自标准输入的意思
#用 root 身份,将 /etc/passwd 与 /etc/shadow 同一行贴在一起
[root@li ~]# paste /etc/passwd /etc/shadow
root:x:0:0:root:/root:/bin/bash root:$6$Wut1Cw0fCGVGBkEF$H/OVyZf7Y00AQEASWVcyFvo2ZBgv4pgH3Qp5QuFH8bOZXKgxZw0CaiZ/bVW2/estLhu4hWJZW6otFsWKS/iEa1::0:99999:7:::
bin:x:1:1:bin:/bin:/sbin/nologin        bin:*:18353:0:99999:7:::
5.4.5、expand

将 [tab] 转成空格键:

[root@li ~]# expand [-t] 文件
选项与参数:
-t:接数字。一般来说,一个 tab 可以用 8 个空格取代。我们可以自定义一个 tab 代表多少字符
[root@li ~]# grep '^MANPATH' /etc/man_db.conf | head -n 3
MANPATH_MAP     /bin                    /usr/share/man
MANPATH_MAP     /usr/bin                /usr/share/man
MANPATH_MAP     /sbin                   /usr/share/man
[root@li ~]# grep '^MANPATH' /etc/man_db.conf | head -n 3 | cat -A
MANPATH_MAP^I/bin^I^I^I/usr/share/man$
MANPATH_MAP^I/usr/bin^I^I/usr/share/man$
MANPATH_MAP^I/sbin^I^I^I/usr/share/man$
#看到差别了吗?[tab] 按键被显示成了 ^I
#承上,将 [tab] 设定为 6 个字符
[root@li ~]# grep '^MANPATH' /etc/man_db.conf | head -n 3 |expand -t 6 - | cat -A
MANPATH_MAP /bin              /usr/share/man$
MANPATH_MAP /usr/bin          /usr/share/man$
MANPATH_MAP /sbin             /usr/share/man$

5.5、分区命令:split

可以帮你把一个大文件,依据文件大小或行数来分区,就可以将大文件分区为小文件了!

[root@li ~]# split [-bl] 文件 PREFIX
选项与参数:
-b:后面接的是分区成的文件大小,可加单位
-l:以行数来分区
PREFIX:前导符
[root@li ~]# cd /tmp; split -b 300k /etc/services services
[root@li tmp]# ll -k services*
-rw-r--r--. 1 root root 307200 8月   6 11:07 servicesaa
-rw-r--r--. 1 root root 307200 8月   6 11:07 servicesab
-rw-r--r--. 1 root root  55893 8月   6 11:07 servicesac
#前导符可以随便写!就会以xxxaa,xxxab,xxxac等方式创建

#将上面三个文件合成一个文件,文件名为 servicesback
[root@li tmp]# cat services* >> servicesback

#使用 ls -al / 输出的信息中,每十行记录成一个文件
[root@li tmp]# ls -al / | split -l 10 - lsroot
[root@li tmp]# wc -l lsroot*
  10 lsrootaa
  10 lsrootab
   2 lsrootac
  22 总用量
#重点在于那个 - !如果需要 stdout/stdin ,但偏偏没有文件,可以使用 - 代表标准输入/输出

5.6、参数代换:xargs

产生某个指令的参数的意思!xargs 可以读入 stdin 的数据,并且以空格符或断行符作为分辨,将 stdin 的资料分隔成为 arguments。

[root@li tmp]# xargs [-Oepn] 指令
参数与选项:
-O:还原特殊字符为一般字符
-e:是 EOF 的意思,后面可以接一个字符,当 xargs 分析到这个字符时,停止工作
-p:每次执行时,都会询问
-n:接次数,每次指令执行时,要使用几个参数的意思
当 xargs 没有接任何指令时,默认是以 echo 来进行输出
[root@li tmp]# cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -n 1 id
uid=0(root) gid=0(root)=0(root)
uid=1(bin) gid=1(bin)=1(bin)
uid=2(daemon) gid=2(daemon)=2(daemon)

[root@li tmp]# cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -p -n 1 id
id root ?...y
uid=0(root) gid=0(root)=0(root)
id bin ?...y
uid=1(bin) gid=1(bin)=1(bin)
id daemon ?...y
uid=2(daemon) gid=2(daemon)=2(daemon)

5.7、关于减号 - 的作用

在管线命令中,常常会用到前一个指令的 stdout 作为这次的 stdin,某些指令需要用到文件名来进行处理,该 stdin 与 stdout 可以利用减号 “-” 来替代

[root@li tmp]# mkdir /tmp/homeback
[root@li tmp]# tar -cv -f - /home | tar -xv -f - -C /tmp/homeback
tar: 从成员名中删除开头的“/”
/home/
/home/li/
/home/li/.bash_logout
/home/li/.bash_profile
/home/li/.bashrc
/home/li/.bash_history
home/
home/li/
home/li/.bash_logout
home/li/.bash_profile
home/li/.bashrc
home/li/.bash_history

你可能感兴趣的:(Linux基础+进阶,linux)