认识与学习BASH

这篇博客详细介绍了BASH Shell的变量功能,包括变量的使用与设置、环境变量、变量范围、键盘读取、数组与声明。还探讨了命令别名设置和Bash shell的操作环境,如路径与命令查找顺序、通配符与特殊符号。此外,讲解了数据流重定向、管道命令以及相关命令如cut、grep、sort、uniq等的使用方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

管理整个计算机硬件的其实是操作系统的内核(kernel),这个内核是需要被保护的。所以一般用户就只能通过Shell来跟内核沟通,以让内核完成我们所想要实现的任务。

命令快速编辑按钮
在这里插入图片描述

一、Shell的变量功能

变量就是以一组文字或符号等,来替换一些设置或一串保留的数据。

1.1、变量的使用与设置:echo、变量设置规则、unset

变量的使用:echo

变量在被使用时,前面必须要加上美元符号【 $ 】,或是以 $ {variable}的方式来使用。

读取变量: echo $variable | ${variable}
[root@VM_0_8_centos ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/python3/bin:/usr/local/mysql/bin:/root/bin
[root@VM_0_8_centos ~]# echo ${HOME}
/root

在bash当中,当一个变量名称尚未被设置时,默认的内容是【空】。变量通过等号(=)进行赋值,且等号两边不能有空格。

[root@VM_0_8_centos ~]# echo ${myname}

[root@VM_0_8_centos ~]# myname=c123
[root@VM_0_8_centos ~]# echo ${myname}
c123

变量的设置规则

  • 变量与变量内容以一个等号【=】来连接
    myname=c123
  • 等号两边不能直接接空格,否则会报错
    错误示例:myname = c123 或 myname=c123 456
  • 变量名称只能是英文字母与数字,但是开头字符不能是数字
    错误示例:1myname=c123
  • 变量内容若有空格可使用双引号【"】或单引号【’】将变量内容结合起来

特殊使用情况

  • 双引号内的特殊字符如 $ 等,可以保持原本的特性
    var=“lang is $LANG” 则 echo $var 输出结果:lang is en_US.utf8

  • 单引号内的特殊字符则为一般字符(纯文本)
    var=‘lang is $LANG’ 则 echo $var 输出结果:lang is $LANG

  • 可用转义符【\】将特殊符号(如[Enter]、$、\、空格、’等)变成一般字符
    myname=c\ 123

  • 在一串命令的执行中,还需要借由其它额外的命令所提供的信息时,可以使用反单引号【` 命令 `】或 【$(命令)】,这些被特殊处理的命令会优先执行

    version=“内核的版号:$(uname -r)” 再echo $version 输出结果:内核版本号:3.10.0-1062.18.1.el7.x86_64

  • 若该变量为扩增变量内容时,则可用"$ 变量名称" 或 “$ {变量}” 或 $ PATH 累加内容
    PATH="$ PATH":/home/bin 或 PATH=$ {PATH}:/home/bin 或 PATH=$ PATH:/home/bin

  • 若该变量需要在其他子程序运行,则需要以export来使变量变成环境变量
    export 自定义变量名称

  • 通常大写字符为系统默认变量,自行设置变量可以使用小写字符

  • 取消变量的方法为使用unset:【unset 变量名称】 例如取消myname的设置
    unset myname

示例:子程序下使用变量

在目前这个shell的情况下,去启用另一个新的shell,新的那个shell就是子程序。

[root@VM_0_8_centos ~]# name=c123
[root@VM_0_8_centos ~]# echo $name
c123
[root@VM_0_8_centos ~]# bash   <== 进入子程序
[root@VM_0_8_centos ~]# echo $name  <== 子程序中输出name变量的值
                                    <== 子程序没有name这个变量,输出为空
[root@VM_0_8_centos ~]# exit        <== 离开子程序
exit
[root@VM_0_8_centos ~]# export name <== 设置name为环境变量
[root@VM_0_8_centos ~]# bash
[root@VM_0_8_centos ~]# echo $name
c123
[root@VM_0_8_centos ~]# exit
exit
[root@VM_0_8_centos ~]# unset name
[root@VM_0_8_centos ~]# echo $name

示例:进入内核模块目录

[root@VM_0_8_centos ~]# cd /lib/modules/$(uname -r)/kernel
[root@VM_0_8_centos kernel]# pwd
/lib/modules/3.10.0-1062.18.1.el7.x86_64/kernel

cd命令进行了两次操作:
1、先进行括号内的操作【uname -r】并得到内核版本 3.10.0-1062.18.1.el7.x86_64
2、将上述的结果带入原命令,故得命令为:cd /lib/modules/3.10.0-1062.18.1.el7.x86_64/kernel

1.2、环境变量的功能

环境变量可以帮我们实现很多功能,包括根目录(主文件夹)的变换、提示字符的显示、执行文件查找的路径等。

用env观察环境变量与常见环境变量说明

[root@VM_0_8_centos ~]# env
XDG_SESSION_ID=18535
HOSTNAME=VM_0_8_centos    <==  主机名称
TERM=xterm                <==  终端使用的环境类型
SHELL=/bin/bash           <==  使用Shell的类型
HISTSIZE=3000             <==  历史命令记录的条数
USER=root                 <==  使用者的名称
LS_COLORS=rs=0:di=01;34:ln=01;...  <== 一些颜色设置
MAIL=/var/spool/mail/root
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/python3/bin:/usr/local/mysql/bin:/root/bin
PWD=/root                  <== 目前使用者所在的工作目录(使用pwd获取)
LANG=en_US.utf8            <== 语系
SHLVL=1
HOME=/root                 <== 使用者的家目录
LOGNAME=root               <== 登录者用来登录的账号名称
_=/usr/bin/env             <== 上一次使用的命令的最后一个参数(或命令本身)

PATH:执行文件查找路径,目录与目录中间以冒号(:)分隔,由于文件的查找是依序由PATH的变量内的目录来查询的,所以,目录的顺序也是重要的。

用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=94                                <== 在目前终端下,使用的栏位由几个字符长度
HISTFILE=/root/.bash_history              <== 历史命令记录的放置文件,隐藏文件
HISTFILESIZE=3000                         <== 存起来(与上个变量有关)的文件之命令的最大记录数
HISTSIZE=3000                             <== 目前环境下,内存中记录的历史命令最大条数
IFS=$' \t\n'                              <== 默认的分隔符号
LINES=31                                  <== 目前的终端下的最大行数
MACHTYPE=x86_64-redhat-linux-gnu          <== 安装的机器类型
OSTYPE=linux-gnu                          <== 操作系统的类型
PS1='[\u@\h \W]\$ '                       <== PS1,命令提示符
PS2='> '                                  <== 如果你使用转义符(\),这是第二行以后的提示字符
$                                         <== 目前这个shell所使用的PID
?                                         <== 刚刚执行完命令的返回值

$:关于本shell的PID

美元符号本身也是个变量。这个符号同样也代表目前这个shell的进程号,即所谓的PID。通过【echo $$】输出PID号码的值。

[root@VM_0_8_centos ~]# echo $$
6684

?:关于上个执行命令的返回值

这个变量是上一个执行的命令所返回的值,重点是【上一个命令】与【返回值】两个地方。当我们执行某些命令时,这些命令都会返回一个执行后的代码。一般来说,如果成功的执行该命令,则会返回0值;如果执行过程发生错误,就会返回错误的代码,一般就是以非0的数值来替换。

[root@VM_0_8_centos ~]# echo $SHELL
/bin/bash                                  <== 顺利显示变量值,没有错误
[root@VM_0_8_centos ~]# echo $?            <== 因为没有错误,所以返回0
0
[root@VM_0_8_centos ~]# 12name=cjw
-bash: 12name=cjw: command not found       <== 发生错误
[root@VM_0_8_centos ~]# echo $?            <== 返回上一条命令执行错误的代码
127
[root@VM_0_8_centos ~]# echo $?            <== 上一条命令执行成功,所有返回0
0

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

自定义变量与环境变量的区别在于【该变量是否会被子进程所继续使用】。子进程仅会继承父进程的环境变量,不会继承父进程的自定义变量。

如果仅执行export而没有接变量时,那么此时将会把所有的环境变量显示出来。

1.3、变量的范围

如果在运行程序的时候,有父进程与子进程的不同进程关系时,则变量可否被引用与export有关,被export后的变量,我们可以称它为环境变量,环境变量可以被子程序所引用,但是其他的自定义变量内容就不会存在于子进程中。

环境变量可被子进程引用的原因:

  • 当启动一个shell,操作系统会分配一内存区给shell使用,此内存中的变量可让子进程使用;
  • 若在父进程利用export功能,可以让自定义变量的内容写到上述的内存区域当中(环境变量);
  • 当加载另一个shell时(即启动子进程,而离开原本的父进程),子shell可以将父shell的环境变量所在的内存区域导入自己的环境变量区域当中。

1.4、变量键盘读取、数组与声明:read、array、declare

read

要读取来自键盘输入的变量,就是用read这个命令。这个命令最常被用在shell脚本的编写当中。

read [-pt] variable
选项与参数:
-p:后面可以接提示符
-t:后面可以接等待的【秒数】

示例

示例一:让使用者由键盘输入一内容,将该内容变成名为atest的变量
[root@VM_0_8_centos ~]# read atest
This is a test
[root@VM_0_8_centos ~]# echo $atest
This is a test

示例二:提示使用者30秒内输入自己的名字,将该输入字符作为名为named的变量内容
[root@VM_0_8_centos ~]# read -p "请输入你的姓名:" -t 30 named
请输入你的姓名:cjw
[root@VM_0_8_centos ~]# echo $named
cjw

declare, typeset

declare 或 typeset 是一样的功能,就是声明变量的类型。如果使用declare后面并没有接任何参数,那么bash就会主动的将所有的变量名称与内容通通显示出来,就好像set一样。

declare [-aixr] variable
选项与参数:
-a:将后面名为variable的变量定义成为数组(array)类型
-i:将后面名为variable的变量定义成为整数(integer)类型
-x:用法与export一样,就是将后面的variable变成环境变量
-r:将变量设置成为readonly类型,该变量不可被更改内容,也不能unset。
示例一:让变量sum进行100+300+50的求和结果
[root@VM_0_8_centos ~]# sum=100+300+50
[root@VM_0_8_centos ~]# echo $sum
100+300+50               <== 定义的变量,默认是字符串格式
[root@VM_0_8_centos ~]# declare -i sum=100+300+50
[root@VM_0_8_centos ~]# echo $sum
450

由于默认情况下,bash对于变量有几个基本的定义

  • 变量类型默认为字符串,所以若不指定变量类型,则1+2为一个字符串而不是计算式
  • bash环境中的数值计算,默认最多仅能到达整数形态,所以1/3结果是0
示例二:将sum变成环境变量
[root@VM_0_8_centos ~]# declare -x sum
[root@VM_0_8_centos ~]# export | grep sum
declare -ix sum="450"

示例三:让sum变成只读属性,不可修改
[root@VM_0_8_centos ~]# declare -r sum
[root@VM_0_8_centos ~]# sum=testing
-bash: sum: 只读变量

示例四:让sum变成非环境变量的自定义变量
[root@VM_0_8_centos ~]# declare +x sum     <== 将-变成+可以进行【取消】操作
[root@VM_0_8_centos ~]# declare -p sum     <== -p可以单独列出变量的类型
declare -ir sum="450"

如果你不小心将变量设置为【只读】,通常要注销再登录才能恢复该变量的类型。

数组(array)变量类型

数组的设置方式

var[index]=content

bash提供的是一维数组,var是数组变量名,index表示数组的下标索引,从1开始

[root@VM_0_8_centos ~]# names[1]="xiao ming"
[root@VM_0_8_centos ~]# names[2]="xiao hong"
[root@VM_0_8_centos ~]# names[3]="xiao zhang"
[root@VM_0_8_centos ~]# echo ${names[1]}
xiao ming
[root@VM_0_8_centos ~]# echo "${names[1]}, ${names[2]}, ${names[3]}"
xiao ming, xiao hong, xiao zhang

数组的读取,使用${var[index]}的形式读取。

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

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

ulimit [-SHacdfltu] [配额]
选项与参数:
-H: hard limit,严格的设置,必定不能超过这个设置的数值。
-S: soft limit,警告的设置,可以超过这个设置值,但是若超过则有警告信息。
	在设置上,通常soft会比hard小,举例来说,soft可设置为80而hard设置为100,
	那么当可以使用到90(因为没有超过100),但介于80~100之间时,系统会有警告信息通知你。
-a:后面不接任何选项与参数,可列出所有的限制额度。
-c:当某些程序发生错误时,系统可能会将该程序在内存中的信息写成文件(除错用),
	这种文件就被称为内核文件(core file)。此为限制每个内核文件的最大容量。
-f:此shell可以建立的最大文件容量(一般可能设置为2GB)单位为Kbytes。
-d:程序可使用的最大段内存(segment)容量
-l:可用于锁定(lock)的内存量
-t:可使用的最大cpu时间(单位秒)
-u:单一使用者可以使用的最大进程(process)数量
列出目前身份的所有限制数据数值
[root@VM_0_8_centos ~]# 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) 7266
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 100001
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) 7266
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

限制使用者仅能建立10MBytes以下的容量文件
[root@VM_0_8_centos ~]# ulimit -f 10240
[root@VM_0_8_centos ~]# ulimit -a | grep 'file size'
core file size          (blocks, -c) 0
file size               (blocks, -f) 10240   <== 最大量为10240Kbytes,相当10Mbytes
[root@VM_0_8_centos ~]# dd if=/dev/zero of=123 bs=1M count=11
文件大小超出限制

1.6、变量内容的删除、取代与替换

变量内容的删除与替换

示例一:让小写的path自定义变量设置的与PATH内容相同
[root@VM_0_8_centos ~]# path=${PATH}
[root@VM_0_8_centos ~]# echo ${path}
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/python3/bin:/usr/local/mysql/bin:/root/bin

示例二:假设我不喜欢local/bin,所以要将前1个目录删除掉,如何显示?
[root@VM_0_8_centos ~]# echo ${path#/*local/bin:}
/usr/sbin:/usr/bin:/usr/local/python3/bin:/usr/local/mysql/bin:/root/bin

示例三:删除前面所有的目录,仅保留最后一个目录
[root@VM_0_8_centos ~]# echo ${path#/*:}   <==  由于一个#仅删除掉最短的那个,所以只删除/usr/local/sbin:
/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/python3/bin:/usr/local/mysql/bin:/root/bin
[root@VM_0_8_centos ~]# echo ${path##/*:}  <== 增加一个#变成##,它变成【删除掉最长的那个数据】
/root/bin

#与##分别代表的含义

  • #:符合替换文字的【最短的】那一个
  • ##:符合替换文字的【最长的】那一个

#和##都是从前面开始删除内容,%表示从后面开始删除内容

示例四:删除最后那个目录,亦即从:到bin为止的字符
[root@VM_0_8_centos ~]# echo ${path%:*bin}   <== 从后开始删除最短的匹配字符
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/python3/bin:/usr/local/mysql/bin

示例五:保留第一个目录
[root@VM_0_8_centos ~]# echo ${path%%:*bin}  <== 从后开始删除最长的匹配字符
/usr/local/sbin

示例六:将path的变量内容的sbin替换成大写SBIN
[root@VM_0_8_centos ~]# echo ${path/sbin/SBIN}   <== 替换一个符合的内容
/usr/local/SBIN:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/python3/bin:/usr/local/mysql/bin:/root/bin
[root@VM_0_8_centos ~]# echo ${path//sbin/SBIN}  <== 替换所有符合的内容
/usr/local/SBIN:/usr/local/bin:/usr/SBIN:/usr/bin:/usr/local/python3/bin:/usr/local/mysql/bin:/root/bin

总结说明
在这里插入图片描述

变量的测试与内容替换

在某些时刻我们常常需要【判断】某个变量是否存在,若变量存在则使用既有的设置,若变量不存在则给与一个常用的设置。

示例一:测试一下是否存在username这个变量,若不存在则给与username内容为root
[root@VM_0_8_centos ~]# echo ${username}
                                                     <== 输出空白,表示username变量不存在
[root@VM_0_8_centos ~]# username=${username-root}    
[root@VM_0_8_centos ~]# echo ${username}
root                                                 <== 由于username不存在,则被设置为root
[root@VM_0_8_centos ~]# username="cjw test"          <== 设置username变量的值
[root@VM_0_8_centos ~]# username=${username-root}
[root@VM_0_8_centos ~]# echo ${username}
cjw test                                             <== username已经设置,输出原来的值

示例二:若username未设置或为空字符,则将username内容设置为root
[root@VM_0_8_centos ~]# username=""
[root@VM_0_8_centos ~]# username=${username-root}
[root@VM_0_8_centos ~]# echo ${username}

[root@VM_0_8_centos ~]# username=${username:-root}
[root@VM_0_8_centos ~]# echo ${username}
root       

测试方法总结

在这里插入图片描述

二、命令别名与历史命令

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

命令别名可以简化长命令,还可以增设默认的选项在一些常用的命令上。

示例一:简化ls -al | more 分页查看所有文件详情的命令
[root@VM_0_8_centos ~]# alias lm='ls -al | more'
[root@VM_0_8_centos ~]# type lm
lm 是 'ls -al | more' 的别名

示例二:增设默认的选项在一些常用的命令上
[root@VM_0_8_centos ~]# alias rm='rm -i'
[root@VM_0_8_centos ~]# type rm
rm'rm -i' 的别名

示例三:查看所有命令别名
[root@VM_0_8_centos ~]# 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='ls -al | more'
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@VM_0_8_centos ~]# unalias lm
[root@VM_0_8_centos ~]# lm
-bash: lm: 未找到命令

那么命令别名与变量有什么不同?

命令别名是新创一个新的命令,你可以直接执行该命令,至于变量则需要使用类似【echo】命令才能够调出变量的内容。

三、Bash shell的操作环境

3.1、路径与命令查找顺序

命令的运行顺序

  1. 以相对/绝对路径执行命令,例如【/bin/ls】 或 【./ls】
  2. 由alias找到该命令来执行
  3. 由bash内置的(builtin)命令来执行
  4. 通过$PATH这个变量的顺序来查找到的第一个命令来执行
查看ls命令的执行顺序
[root@VM_0_8_centos ~]# type -a ls
ls 是 `ls --color=auto' 的别名
ls 是 /usr/bin/ls

3.2、通配符与特殊符号

常用通配符

在这里插入图片描述

特殊符号

在这里插入图片描述

四、数据流重定向

数据流重定向就是将某个命令执行后应该要出现在屏幕上的数据,给它传输到其它地方,例如文件或是设备。

4.1、什么是数据流重定向

standard output 与 standard error output

标准输出指的是命令执行所返回的正确信息,而标准错误输出可理解为命令执行失败后,所返回的错误信息。

重定向的字符

  • 标准输入(stdin):代码为0,使用<或<<
  • 标准输出(stdout):代码为1,使用>或>>
  • 标准错误输出(stderr):代码为2,使用2>或2>>
示例:将stdout与stderr分别存到不同的文件中,切换到
[root@VM_0_8_centos ~]# find /home -name .bashrc > list_right 2> list_error

/dev/null 垃圾桶黑洞设备与特殊写法

/dev/null 可以吃掉任何导向这个设备的信息

将错误的数据丢弃,屏幕上显示正确的数据
find /home -name .bashrc 2> /dev/null

将命令的数据全部写入名为list的文件中
find /home -name .bashrc > list 2>&1

standard input:< 与 <<

将原本需要由键盘输入的数据,改由文件内容来替换。< 就是标准输入,<< 代表【结束的输入符】

[root@VM_0_8_centos ~]# cat > catfile << "eof"
> This is a test
> Ok or stop
> eof     <== 输入关键词,立刻就结束而不需要输入[ctrl]+d
[root@VM_0_8_centos ~]# cat catfile
This is a test
Ok or stop

4.2、$?(命令返回值) 与 $$ 或 ||

在这里插入图片描述

由于命令是一个接着一个去执行的,因此,如果真要使用判断,那么这个&&与||的顺序就不能搞错。一般来说,假设判断式有三个, command1 && command2 || command3顺序通常不会变,而且command2和command3会使用肯定可以执行成功的命令。

五、管道命令(pipe)

管道命令【|】仅能处理经由前面一个命令传来的正确信息,也就是标准输出的信息,对于标准错误并没有直接处理的能力。

在每个管道后面接的第一个数据必定是【命令】,而且这个命令必须要能接受标准输入的数据才行,这样的命令才可以为管道命令。

5.1、选取命令:cut、grep

选取命令,就是将一段数据经过分析后,取出我们想要的,或是经由分析关键词,取得我们所想要的那一行。一般来说,选取信息通常是针对【一行一行】来分析的,并不是整篇信息分析。

cut

将一段信息的某一段给它【切】出来,处理的信息是以【行】为单位的。

cut -d '分隔字符' -f fields <== 用于有特定分隔字符
cut -c '字符区间'  <== 用于排列整齐的信息
选项与参数:
-d:后面接分隔字符,与-f一起使用
-f:根据-d的分隔字符将一段信息划分成为数段,用-f取出第几段的意思
-c:以字符(characters)的单位取出固定字符区间
示例一:将PATH变量取出,找出第五个路径
[root@VM_0_8_centos ~]# echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/local/python3/bin:/usr/local/mysql/bin:/root/bin
[root@VM_0_8_centos ~]# echo $PATH | cut -d ':' -f 5
/usr/local/python3/bin
[root@VM_0_8_centos ~]# echo $PATH | cut -d ':' -f 3,5    <== 列出第3与第5个路径
/usr/sbin:/usr/local/python3/bin


示例二:将export输出的信息,取得第12个字符以后的所有字符
[root@VM_0_8_centos ~]# export | cut -c 12-    <== 12- 代表从第12个字符到最后一个字符的区间
HISTSIZE="3000"
HISTTIMEFORMAT="%F %T "
HOME="/root"
HOSTNAME="VM_0_8_centos"
LANG="zh_CN.utf8"
LESSOPEN="||/usr/bin/lesspipe.sh %s"
LOGNAME="root"
...


示例三:用last将显示的登录者的信息中,仅留下使用者大名
[root@VM_0_8_centos ~]# last | cut -d ' ' -f 1
root
root
root
...

cut在处理多空格相连的数据时,可能会比较吃力一点,后面会使用awk来替换。

grep

cut是将一行信息当中,取出某部分我们想要的,而grep则是分析一行信息,若当中有我们所需要的信息,就将该行拿出来。

grep [-acinv] [--color=auto] '查找字符' filename
选项与参数:
-a:将二进制文件以文本文件的方式查找数据
-c:计算找到'查找字符'的次数
-i:忽略大小写的不同,所以大小写相同
-n:输出行号
-v:反向选择,亦即显示出没有'查找字符'内容的那一行
--color=auto:可以将找到的关键字部分加上颜色的显示
示例一:将last当中,有出现root的那一行就显示出来
[ck187420@shell.ceshiren.com ~]$ last | grep 'root'

示例二:与示例一相反,只要没有root的就列出来
[ck187420@shell.ceshiren.com ~]$ last | grep -v 'root'

示例三:在last的输出信息中,只要有root就取出,并且仅取第一栏
[ck187420@shell.ceshiren.com ~]$ last | grep 'root' | cut -d ' ' -f 1

示例四:取出/etc/man_db.conf内含MANPATH的那几行
[ck187420@shell.ceshiren.com ~]$ grep --color=auto 'MANPATH' /etc/man_db.conf 

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

sort

可以根据不同的数据形式来排序,例如数字与文字的排序就不一样。排序的字符与语系的编码有关,因此,如果需要排序时,建议使用LANG=C来让语系统一。

sort [-fbMnrtuk] [file or stdin]
选项与参数:
-f:忽略大小写的差异,例如A与a视为编码相同
-b:忽略前面的空格字符部分
-M:以月份的名字来排序,例如JAN,DEC等的排序方法
-n:使用【纯数字】进行排序(默认是以文字形式来排序的)
-r:反向排序
-u:就是uniq,相同的数据中,仅出现一行代表
-t:分隔符号,默认是用【Tab】键来分隔
-k:以哪个区间(field)来进行排序的意思
示例一:个人账号都记录在/etc/passwd下,请将账号进行排序
[root@VM_0_8_centos ~]# cat /etc/passwd | sort
abrt:x:173:173::/etc/abrt:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
bin:x:1:1:bin:/bin:/sbin/nologin
...

示例二:/etc/passwd是以:分隔的,使用第三栏进行排序
[root@VM_0_8_centos ~]# cat /etc/passwd | sort -t ':' -k 3
root:x:0:0:root:/root:/bin/bash
mysql:x:1000:1000::/home/mysql:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

[root@VM_0_8_centos ~]# cat /etc/passwd | sort -t ':' -k 3 -n  <== 以数字排列
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin


示例三:利用last,将输出的数据仅显示账号,并加以排序
[root@VM_0_8_centos ~]# last | cut -d ' ' -f 1 | sort

uniq

将重复的数据仅列出一个显示

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

示例二:列出每个人登录总次数
[root@VM_0_8_centos ~]# last | cut -d ' ' -f 1 | sort | uniq -c
      2 reboot
    131 root
      1 wtmp

wc

计算输出信息的整体数据

wc [-lwm]
选项与数据:
-l:仅列出行
-w:仅列出多少字(英文字母)
-m:多少字符
示例一:计算/etc/man_db.conf里面有多少相关行、字数、字符数
[root@VM_0_8_centos etc]# cat /etc/man_db.conf | wc
    131     723    5171    <== 分别代表 行、字数、字符数

示例二:取出登录系统的总人数
last 会输出空白行,wtmp、unknown、reboot等无关账号登录信息,需要使用grep过滤
[ck187420@shell.ceshiren.com ~]$ last | grep [a-zA-Z0-9] | grep -v 'wtmp' | grep -v 'reboot' | grep -v 'unknown' | wc -l
1209

5.3、双向重定向:tee

tee会同时将数据流分送到文件与屏幕(screen),而输出到屏幕的,就是stdout。

tee [-a] file
选项与参数:
-a:以累加(append)的方式,将数据加入file当中

示例一:ls的数据保存到~/homefile,同时屏幕也有输出信息
[root@VM_0_8_centos ~]# ls -l /home | tee homefile | more
总用量 2113032
-rw-r--r--  1 root  root   127431820 731 2020 jdk-8u261-linux-x64.rpm
-rw-r--r--  1 root  root    66244250 731 2020 jenkins-2.235.3-1.1.noarch.rpm
drwx------  2 mysql mysql       4096 1230 17:13 mysql
...


示例二:查看根目录的信息,并把数据累加到homefile文件中
[root@VM_0_8_centos ~]# ls -l / | tee -a homefile | more
总用量 80
lrwxrwxrwx.  1 root root     7 37 2019 bin -> usr/bin
drwxr-xr-x   2 root root  4096 526 15:23 bitnami
dr-xr-xr-x.  5 root root  4096 522 10:24 boot
...

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

tr
tr 可以用来删除一段信息当中的文字,或是进行文字信息的替换。

tr [-ds] SET1 ...
选项与参数:
-d:删除信息当中的SET1这个字符
-s:替换掉重复的字符
示例一:将last输出信息中,所有小写变成大写字符
[root@VM_0_8_centos ~]# last | tr '[a-z]' '[A-Z]'    <== '[a-z]'外面的单引号可以去除,同样可以执行
...
ROOT     PTS/0        117.147.40.136   SUN JUL 12 12:42 - 14:03  (01:21)    
REBOOT   SYSTEM BOOT  3.10.0-1062.18.1 SUN JUL 12 12:40 - 11:22 (328+22:41) 


示例二:将/etc/passwd输出信息中,将冒号(:)去除
[root@VM_0_8_centos ~]# cat /etc/passwd | tr -d ':'
rootx00root/root/bin/bash
binx11bin/bin/sbin/nologin
...

col

col [-x]
选项与参数:
-x:将tab键转换成对等的空格键
示例:利用cat -A 显示出所有特殊键,最后以col将[tab]转成空白
[root@VM_0_8_centos ~]# cat -A /etc/man_db.conf     <== ^I就是tab
[root@VM_0_8_centos ~]# cat /etc/man_db.conf | col -x | cat -A | more
...
MANPATH_MAP     /bin                    /usr/share/man$
MANPATH_MAP     /usr/bin                /usr/share/man$
MANPATH_MAP     /sbin                   /usr/share/man$
...

join

join(加入/参加)用于处理两个文件之间的数据,主要是处理【两个文件当中,有相同数据的那一行,才将它加在一起】。

join [-ti12] file1 file2
选项与参数:
-t: 默认以空格字符分隔数据,并且比对【第一个栏位】的数据,如果两个文件相同,则将两条数据连成一行,且第一个栏位放在第一个
-i:忽略大小写的差异
-1:这个是数字1,代表【第一个文件要用哪个栏位来分析】的意思
-2:代表【第二个文件要用哪个栏位来分析】的意思
示例一:用root的身份,将/etc/passwd与/etc/shadow相关数据整合成一栏
[root@VM_0_8_centos ~]# 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:$1$nyolCDqA$1ZQ5QnXtFDfsXQT3oEo1x/:18455:0:99999:7:::
bin:*:17834:0:99999:7:::
daemon:*:17834:0:99999:7:::
由输出的数据可以发现这两个文件的最左边栏位都是相同账号,且以:分隔

[root@VM_0_8_centos ~]# join -t ':' /etc/passwd /etc/shadow | head -n 3
root:x:0:0:root:/root:/bin/bash:$1$nyolCDqA$1ZQ5QnXtFDfsXQT3oEo1x/:18455:0:99999:7:::
bin:x:1:1:bin:/bin:/sbin/nologin:*:17834:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin:*:17834:0:99999:7:::
第二个文件的相同栏位并不会显示,因为已经在最左边的栏位出现了

示例二:/etc/passwd第四个栏位是GID,这个GID记录在/etc/group当中的第三个栏位,整合这两个文件
[root@VM_0_8_centos ~]# 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@VM_0_8_centos ~]# join -t ':' -1 4 /etc/passwd -2 3 /etc/group | head -n 3
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:

此外,需要特别注意的是,在使用join之前,你所需要处理的文件应该要事先经过排序(sort)处理,否则有些比对项目就会被忽略。

paste

作用:直接将两行贴在一起,且中间以[Tab]键隔开

paste [-d] file1 file2
选项与参数:
-d:后面可以接分隔字符,默认是以[Tab]来分隔
-:如果file部分写成-,表示来自标准输入的数据的意思
示例一:用root身份,将/etc/passwd与/etc/shadow同一行贴在一起
[root@VM_0_8_centos ~]# paste /etc/passwd /etc/shadow
root:x:0:0:root:/root:/bin/bash	root:$1$nyolCDqA$1ZQ5QnXtFDfsXQT3oEo1x/:18455:0:99999:7:::
bin:x:1:1:bin:/bin:/sbin/nologin	bin:*:17834:0:99999:7:::
daemon:x:2:2:daemon:/sbin:/sbin/nologin	daemon:*:17834:0:99999:7:::
adm:x:3:4:adm:/var/adm:/sbin/nologin	adm:*:17834:0:99999:7:::
...

示例二:先将/etc/group读出,然后与示例一贴在一起,且仅取出前三行
[root@VM_0_8_centos ~]# cat /etc/group | paste /etc/passwd /etc/shadow -| head -n 3
root:x:0:0:root:/root:/bin/bash	root:$1$nyolCDqA$1ZQ5QnXtFDfsXQT3oEo1x/:18455:0:99999:7:::	root:x:0:
bin:x:1:1:bin:/bin:/sbin/nologin	bin:*:17834:0:99999:7:::	bin:x:1:
daemon:x:2:2:daemon:/sbin:/sbin/nologin	daemon:*:17834:0:99999:7:::	daemon:x:2:

expand

作用:将[Tab]按键转成空格键

expand [-t] file
选项与参数:
-t:后面可以接数字,一般来说一个Tab按键可以用8个空格键替换,我们也可以自定义一个[Tab]按键代表多少个字符
示例一:将/etc/man_db.conf内行首为MANPATH的字样就取出,仅取前三行
[root@VM_0_8_centos ~]# 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@VM_0_8_centos ~]# 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$   <== [Tab]键显示成^I
MANPATH_MAP^I/sbin^I^I^I/usr/share/man$


示例三:承上,将[Tab]按键设置成6个字符
[root@VM_0_8_centos ~]# 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

split 可以帮助将一个大文件,依据文件大小或行数来划分,就可以将大文件划分成为小文件了。

split [-bl] file PERFIX
选项与参数:
-b:后面可接欲划分成的文件大小,可加单位,例如b、k、m等
-l:以行数来进行划分
PERFIX: 代表前缀字符的意思,可作为划分文件的前缀文字
示例一:将/etc/services拆分成300k一个文件
[root@VM_0_8_centos ~]# split -b 300k /etc/services services
[root@VM_0_8_centos ~]# ll -h services*
-rw-r--r-- 1 root root 300K 66 19:33 servicesaa
-rw-r--r-- 1 root root 300K 66 19:33 servicesab
-rw-r--r-- 1 root root  55K 66 19:33 servicesac

示例二:将拆分出来的三个小文件合成一个文件,名称为servicesback
[root@VM_0_8_centos ~]# cat services* >> servicesback
[root@VM_0_8_centos ~]# ll -h servicesback
-rw-r--r-- 1 root root 655K 66 19:37 servicesback

示例三:使用 ls -al / 输出的信息中,每十行记录成一个文件
[root@VM_0_8_centos ~]# ls -al / | split -l 10 - lsroot
[root@VM_0_8_centos ~]# wc -l lsroot*
  10 lsrootaa
  10 lsrootab
   6 lsrootac
  26 总用量

5.6、参数代换:xargs

xargs 用于产生某个命令的参数的意思。xargs 可以读入stdin 的数据,并且以空格符或换行符作为标识符,将stdin的数据分隔成为参数。因为是以空格符作为分隔,所以,如果有一些文件名或其他意义的名词内含有空格符的时候,xargs可能就会误判了。

xargs [-0epn] command
选项与参数:
-0:如果输入的stdin含有特殊字符,例如`、\、空格等字符,这个-0参数可以将它还原成一般字符,这个参数可以用于特殊状态。
-e:这是EOF(end of line),后面可以接一个字符,当xargs分析到这个字符时,就会停止工作
-p:在执行每个命令时,都会询问使用者的意思
-n:后面接次数,每次command命令执行时,要使用几个参数的意思

当xargs后面没有接任何的命令时,默认是以echo来进行输出

示例一:将/etc/passwd内的第一栏取出,仅取出三行,使用id这个命令将每个账号内容显示来
[root@VM_0_8_centos ~]# 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)

示例二:每次执行id时,都要询问使用者是否操作
[root@VM_0_8_centos ~]# 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)


示例三:将所有的/etc/passwd内的账号都以id查看,但查到sync就结束命令串
需要注意的是,-e'sync'是连在一起
[root@VM_0_8_centos ~]# cut -d ':' -f 1 /etc/passwd | xargs -e'sync' -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)
uid=3(adm) gid=4(adm)=4(adm)
uid=4(lp) gid=7(lp)=7(lp)

要使用xargs的原因是,很多命令其实并不支持管道命令,因此可以通过xargs来提供该命令使用标准输入

示例四:找出/usr/sbin 下面具有特殊权限的文件名,并使用ls -l 列出详细属性
[root@VM_0_8_centos ~]# find /usr/sbin -perm /7000 | xargs ls -l
-rwxr-sr-x  1 root root      11224 89 2019 /usr/sbin/netreport
-rwsr-xr-x. 1 root root      11216 411 2018 /usr/sbin/pam_timestamp_check
-rwxr-sr-x. 1 root postdrop 218632 1031 2018 /usr/sbin/postdrop
...

5.7、关于减号【 - 】的用途

在管道命令当中,常常会使用到前一个命令的stdout作为这次的stdin,某些命令需要用到文件名(例如tar)来进行处理时,该stdin与stdout可以利用减号’-'来替代。

[root@VM_0_8_centos homeback]# mkdir /tmp/homeback
[root@VM_0_8_centos homeback]# tar -cvf - /home | tar -xvf - -C /tmp/homeback

鸟哥的私房菜

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值