第十章 认识与学习BASH
10.1 Bash与Shell
命令别名设置功能:
alias lm='ls -al' 给命令ls -al一个别名lm。注意,等号两端不能有多余空格
查询命令是否是Bash shell的内置命令:type
type [-tpa] name
-t 此时,file表明命令为外部命令;
alias表明命令是命令别名设置的命令;
builtin表明该命令为bash内置的命令功能
-p 如果后面接的name是外部命令时,才会显示完整文件名
-a 会有PATH变量定义的路径中,将所有含有name的命令都列出来,包含alias
命令的执行与快速编辑按钮:
使用反斜线+回车: \+[Enter] 能够让命令换行输入
Ctrl + u 从光标向前删除命令串
Ctrl + k 从光标向后删除命令串
Ctrl + a 让光标移动到整个命令串的最前面
Ctrl + e 从光标移动到整个命令串的最后面
10.2 Shell的变量功能
10.2.1 变量概念
变量,让某一个特定的字符串代表不固定的内容。
变量具有可变性,使用方便。
影响bash环境操作的变量,PATH,HOME,MAIL,SHELL。
10.2.2 变量的使用基础
变量的使用与设置:
echo $variable 显示变量代表的内容
echo $PATH 显示PATH变量的内容
echo ${PATH} 同上,显示PATH变量的内容
设置变量:
[dj@study ~]$ echo ${myname} 此时myname变量是不存在的,是空的;不要随便显示一个不存在的变量,其他的shell中可能会报错
[dj@study ~]$ myname=dj 将myname设置为dj,等号两边不能有空格
[dj@study ~]$ echo ${myname} 输出myname
dj
变量设置规则:
var双引号内的特殊字符,保留原本的特性
单引号内的特殊字符,仅为一般字符(纯文本)
[dj@study ~]$ var="lang is $LANG" 双引号
[dj@study ~]$ var2='lang is $LANG' 单引号
[dj@study ~]$ echo $var 双引号中的特殊字符,是特殊含义
lang is zh_CN.UTF-8
[dj@study ~]$ echo $var2 单引号中的特殊字符,是普通文本
lang is $LANG
获得内核版本:
[dj@study ~]$ version=$(uname -r)
[dj@study ~]$ echo $version
3.10.0-1062.el7.x86_64
累加变量内容:
PATH=$PATH:/home/bin
或者:
PATH="$PATH":/home/bin
或者:
PATH=${PATH}:/home/bin
若该变量需要在其他子程序中智行,需要使用 export 使变量变成环境变量:
export PATH
取消myname变量:
unset myname
export可以使父进程中定义的变量在子进程中生效:
name=dj
echo $name 输出dj
bash 进入子进程
echo $name 输出空
exit 退出子进程
export name 使name变量生效!!!这样就可以在其他进程中生效
bash 进入子进程
echo $name 这次可以输出dj
exit 退出子进程
进入你目前内核的模块目录:先获取当前的内核版本,输入到路径名称中组合成完整路径名
cd /lib/modules/`uname -r`/kernel 两法功能相同
cd /lib/modules/$(uname -r)/kernel 该法更优
先用locate
将文件名数据列出来,再用ls
输出详细信息:
[dj@study kernel]$ ls -ld $(locate crontab)
-rw-------. 1 root root 541 8月 9 2019 /etc/anacrontab
-rw-r--r--. 1 root root 451 6月 10 2014 /etc/crontab
-rwsr-xr-x. 1 root root 57656 8月 9 2019 /usr/bin/crontab
drwxr-xr-x. 2 root root 21 4月 29 21:33 /usr/share/doc/man-pages-overrides-7.7.3/crontabs
-rw-r--r--. 1 root root 17738 8月 9 2019 /usr/share/doc/man-pages-overrides-7.7.3/crontabs/COPYING
-rw-r--r--. 1 root root 2626 8月 9 2019 /usr/share/man/man1/crontab.1.gz
-rw-r--r--. 1 root root 4229 6月 10 2014 /usr/share/man/man1p/crontab.1p.gz
-rw-r--r--. 1 root root 1121 6月 10 2014 /usr/share/man/man4/crontabs.4.gz
-rw-r--r--. 1 root root 1658 8月 9 2019 /usr/share/man/man5/anacrontab.5.gz
-rw-r--r--. 1 root root 4980 8月 9 2019 /usr/share/man/man5/crontab.5.gz
-rw-r--r--. 1 root root 2566 8月 9 2019 /usr/share/vim/vim74/syntax/crontab.vim
简化工作目录路径查找:
work="/home/dj/dingjing/darknet"
cd $work
10.2.3 环境变量的功能
列出目前的shell环境下的所有环境变量与其内容:
env
或:
export
echo $RANDOM 输出随机数值
declare -i number=$RANDOM*10/32768;echo $number 输出0-9之间的数值
修改终端命令开头的提示符:
[dj@study ~]$ cd /home
[dj@study home]$ PS1='[\u@\h \w \A #\#]\$'
[dj@study /home 13:39 #22]$
恢复回去:
[dj@study /home 13:39 #22]$PS1='[\u@\h \W]\$'
[dj@study home]$
写CSDN博客时,常常会复制命令行的命令和执行结果到CSDN的bash代码段中,那个井号键每次都会被作为注释符,将该行后面的有效内容注释掉,PS1='[\u@\h \W]$'
,将井号键修改成美元符号:
[root@study ~] PS1='[\u@\h \W]$ ' 结尾最好带个空格
[root@study ~]$
但是这只是一时的,登出后,在进入root环境,又变成老样子井号键,可以写入root的环境配置文件:
[root@study ~] vim ~/.bashrc
PS1='[\u@\h \W]$ ' 把这句加进去
[root@study ~]$ 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
PS1='[\u@\h \W]$ '
[root@study ~] source ~/.bashrc 让文件生效
[root@study ~]$ exit
登出
[dj@study ~]$ su -
密码:
上一次登录:,,,,
[root@study ~]$ 登出后再进入还是OK的
美元符号$,本身就是个变量,代表目前这个shell的进程号(PID):
echo $$ 得到当前shell的PID号码
问号?,本身也是个变量,能够获得【上个命令】的【返回值】:
[dj@study home]$echo $SHELL 正确执行
/bin/bash
[dj@study home]$echo $? 返回0
0
[dj@study home]$12name=dj 错误执行
bash: 12name=dj: 未找到命令...
[dj@study home]$echo $? 返回非0
127
[dj@study home]$echo $? 上个命令正确执行,返回0
0
较高级的硬件通常会向下兼容老版本的软件,但是较高级的软件可能无法在旧机器上安装。
export:自定义变量转换成环境变量
env和set差异在于,该变量是否会被子进程所继续引用。
子进程仅会继承父进程的环境变量,子进程不会继承父进程的自定义变量。
为了让父进程中的自定义变量,能用在子进程中,使用export将其变成环境变量:
export 父进程中的自定义变量
10.2.4 影响显示结果的语系变量(locale)
修改语系时,主要修改两个变量:LANG 和 LC_ALL
locale -a 查看支持的语系种类
cat /etc/locale.conf 整体系统默认的语系定义在/etc/locale.conf中
暂时修改中文语系为英文语系:
locale 显示一下看看
LANG=en_US.utf8;locale 设置LANG
export LC_ALL=en_US.utf8;locale 设置LC_ALL
10.2.5 变量的有效范围
就是父进程中的环境变量可以被子进程所引用;父进程中的自定义变量却不能。
这涉及内存配置的原因:
(1)启动一个shell的时候,系统分配一块内存给这个shell用,这块内存中的变量可以给子进程使用;
(2)父进程利用export功能,将自定义变量的内容写入到这块内存区域(环境变量);
(3)在加载另一个shell的时候(即离开父进程,启动子进程),子shell可以将父shell的环境变量所在内存区域导入自己的环境变量区块中。
10.2.6 变量的键盘读取、数组与声明:read、array、declare
read [-pt] variable
-p 后面可以接提示字符
-t 后面可以接等待的秒数,不会一直等待使用者
读入用户输入的一个自定义变量atest:
[dj@study home]$read atest
this is a test
[dj@study home]$echo ${atest}
this is a test
等待10秒钟的时间,将用户输入的信息保存为自定义变量named中;
但是,如果超过10s没有输入,相当于输入了空字符串!
[dj@study home]$read -p "please input your name:" -t 10 named
please input your name:dj
[dj@study home]$echo ${named}
dj
declare [-aixr] variable
-a 将后面名为variable的变量定义为数组array类型
-i 将后面名为variable的变量定义为整数integer类型
-x 用法同export,将后面的变量variable变成环境变量
-r 将变量设置成为readonly类型,该变量不可被更改内容,也不能unset
以整数形式显示得到的结果:
[dj@study ~]$sum=10+20
[dj@study ~]$echo $sum
10+20
[dj@study ~]$declare -i sum=10+20
[dj@study ~]$echo $sum
30
默认情况下,bash会将变量类型默认为字符串;bash环境中的数值计算只能达到整数形态,1/3结果是0。如果需要非字符串的变量,就得进行变量声明。
declare -x sum 将sum声明成环境变量
export | grep sum 显示出来看看
declare -r sum 让sum变成只读属性,不可修改;只能注销后再次登录才能恢复该变量的类型
sum=testing 会报错,提醒说这个变量不能修改!
declare +x sum 取消sum的环境变量资格,将其变成自定义变量
declare -p sum -p可以单独列出变量的类型
[dj@study ~]$declare -p sum
declare -irx sum="30" 本来是这个
[dj@study ~]$declare +x sum 取消其环境变量资格
[dj@study ~]$declare -p sum
declare -ir sum="30" 现在是这个
数组的使用:
var[index]=content 给数组中的指定下标的元素赋值
数组的赋值与显示:
[dj@study ~]$ var[1]="small ming"
[dj@study ~]$ var[2]="big ming"
[dj@study ~]$ var[3]="nice ming"
[dj@study ~]$ echo "${var[1]},${var[2]},${var[3]}"
small ming,big ming,nice ming
10.2.7 与文件系统及程序的限制关系:ulimit
ulimit
是bash
用于限制用户的某些系统资源的,包括:
可以开启的文件数量;
可以使用的CPU时间
可以使用的内存总量等
ulimit [-SHacdfltu] [配额]
-H 严格的设置,必定不能超过这个阈值
-S 警告的设置(soft limit),可以超过该阈值,但是超过后会有警告信息,比-H的小,提前预警
-a 后面不接任何选项或参数,可列出所有的限制额度
-c 当某些程序发生错误时,系统可能会将该程序在内存中的信息写成文件(除错用),这就是内核文件,此项为了设置每个内核文件的最大容量
-f 此shell可以建立的最大文件容量,单位kb,一般大小为2G
-d 程序可以使用的最大段内存容量segment?
-l 可用于锁定(lock)的内存量?
-t 可食用的最大CPU时间,单位s
-u 单一使用者可以使用的最大进程数量
列出你目前普通用户的所有限制数据的数值:
[dj@study ~]$ 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) 3756
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) 3756
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
限制使用者仅能建立10MB以下容量的文件:
ulimit -f 10240
ulimit -a | grep 'file size'
[dj@study ~]$dd if=/dev/zero of=123 bs=1M count=20 尝试建立一个20M的文件,失败了
文件大小超出限制(吐核)
[dj@study ~]$rm 123 删掉这个失败的文件,必须注销后登录,才能解除10M的限制
10.2.8 变量内容的删除、取代、替换
删掉path中包含local/bin的部分:
从头到尾去查找,看看是否有 /*local/bin: 的内容,将找到的最短的一条匹配内容删掉:
[dj@study ~]$ path=${PATH}
[dj@study ~]$ echo ${path}
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/home/dj/.local/bin:/home/dj/bin
[dj@study ~]$ echo ${path#/*local/bin:}
/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/home/dj/.local/bin:/home/dj/bin
删除最短的符合要求的内容:(只有一个井号键#)
[dj@study ~]$ echo ${path#/*:}
/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/home/dj/.local/bin:/home/dj/bin
删除最长的符合要求的内容:(要有两个井号键##)
[dj@study ~]$ echo ${path##/*:}
/home/dj/bin
从后往前匹配:用百分号%
[dj@study ~]$ echo ${path%:*bin} 其实是删除了最后一个目录
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/home/dj/.local/bin
[dj@study ~]$ echo ${path%%:*bin} 其实是保留了第一个目录
/usr/local/bin
变量中的内容替换:
[dj@study ~]$ echo ${path/sbin/SBIN} 一个斜杠/只替换第一处匹配
/usr/local/bin:/usr/local/SBIN:/usr/bin:/usr/sbin:/bin:/sbin:/home/dj/.local/bin:/home/dj/bin
[dj@study ~]$ echo ${path//sbin/SBIN} 两个斜杠//替换全部匹配
/usr/local/bin:/usr/local/SBIN:/usr/bin:/usr/SBIN:/bin:/SBIN:/home/dj/.local/bin:/home/dj/bin
小结:
变量设置方式 | 说明 |
---|---|
${变量#关键词} | 从头开始匹配,将符合的最短匹配删除 |
${变量##关键词} | 从头开始匹配,将符合的最长匹配删除 |
${变量%关键词} | 从后开始匹配,将符合的最短匹配删除 |
${变量%%关键词} | 从后开始匹配,将符合的最长匹配删除 |
${变量/旧字符串/新字符串} | 从头开始匹配,将第一个匹配的旧字符串替换 |
${变量//旧字符串/新字符串} | 将所有匹配的旧字符串替换为新字符串 |
username=${username-root} 如果username为空,输出root,否则输出本来的值;对于空字符串无能为力
username=${username:-root} 如果username为空或为空字符串,输出root
判断变量是否存在:
[dj@study ~]$ unset str;var=${str?novar} 取消str变量;判断str变量是否存在
bash: str: novar 显然不存在,报了错
[dj@study ~]$ str="oldvar";var=${str?novar} 给str变量赋值,使其存在且非空;判断str变量是否存在,没有报错,说明str存在
[dj@study ~]$ echo "var=${var},str=${str}" 查看str变量
var=oldvar,str=oldvar
书本第333页的表格,内容太多了。想不起来就自行翻书吧。
10.3 命令别名与历史命令
10.3.1 命令别名设置:alias、unalisas
alias 列出所有的命令别名
alias rm='rm -i' 删除前询问
alias lm='ls -al| more' 查看文件设置信息
alias vi='vim' 自动打开vim
alias cls='clear' 清屏
alias dir='ls -l' 列出目录和文件
unalias lm 取消lm='ls -al| more'的命令
10.3.2 历史命令:history
alias h='history' 输入h等于输入了history
history [n] 列出最近的n条命令
history [-c] 将目前的shell中所有history内容完全删除
history [-raw] histfiles
-r 将histfiles的内容读到当前这个shell的history记录中
-a 将目前新增的history命令新增入histfiles中,若没有加入histfiles中,则默认写入~/.bash_history
-w 将目前的history记录内容写入histfiles中
[dj@study ~]$ history 3 查看最近3条命令
194 alias
195 h
196 h 3
[dj@study ~]$ history -w 默认将当前历史命令写入~/.bash_history
[dj@study ~]$ echo ${HISTSIZE} 共有1000条历史命令
1000
!! 两个感叹号,执行最近执行过的命令
!195 再次执行当前历史中的编号为195的那条命令
!al 执行最近以al为开头的命令
需要小心安全问题,尤其是root的历史记录文件,那是Cracker的主要攻击对象
同一个账号同时开启多个bash终端,这几个终端的身份都是root,存在~/.bash_history写入问题!
最后注销的那个bash才会是最后写入的数据,其他的终端内的bash命令就不会被记录(其实有被记录,只是被后来的最后一个bash所覆盖更新了)。
因此,尽量使用单一bash登录!!
强制更新记录文件:
history -c
history -w
10.4 Bash shell的操作环境
登录主机时,屏幕上的说明文字、登录时给予用户一些信息或欢迎文字、习惯的环境变量和命令别名等,希望能在登录的时候就设置好。系统全局设置、个人喜好设置,仅是一些文件放置的地点不同。
10.4.1 路径与命令查找顺序
基本顺序:
- 以
相对/绝对顺序
执行命令,如/bin/ls 或 ./ls - 由
alias
找到该命令来执行 - 由bash内置的命令(
builtin
)来执行 - 通过
$PATH
这个变量的顺序查找到的第一个命令来执行
[dj@study ~]$ alias echo='echo -n'
[dj@study ~]$ type -a echo
echo 是 `echo -n' 的别名
echo 是 shell 内嵌
echo 是 /usr/bin/echo
echo 是 /bin/echo
10.4.2 bash的登录与欢迎信息:/etc/issue、/etc/motd
[dj@study ~]$ cat /etc/issue
\S
Kernel \r on an \m
issue内代码 | 意义 |
---|---|
\d | 本地时间日期 |
\l | 小写的字母L,显示第几个终端界面 |
\m | 显示硬件的等级(i386、i486、i586…) |
\n | 显示主机的网络名称 |
\O | 显示domain name |
\r | 操作系统的版本(相当于uname -r) |
\t | 显示本地端时间的时间 |
\S | 操作系统的名称 |
\v | 操作系统的版本 |
通过修改/etc/issue
文件,按照需要的展示形式去展示。
使用telnet远程登录时看到的界面,是在/etc/issue.net
文件中设置的。
想让用户登录后获取一些信息,例如你想要大家都知道的信息,那么可以将信息加入/etc/motd
文件。例如当登录后告诉登录者,系统将会在某个固定时间进行维护工作(一定要是root的身份才能修改):
vim /etc/motd
写入需要展示的内容,保存退出。
10.4.3 bash的环境配置文件
10.4.3-1 输入用户名和密码——进入login shell
——
(1)全局配置:主要读取/etc/profile
/etc/profile
,这是系统的整体设计,会依序调用外部的配置文件——
/etc/profile.d/*.sh
(主要是bash界面颜色、语系、各种命令别名设置等)——
/etc/locale.conf
(主要是LANG和LC_ALL)——
/usr/share/bash-completion/completions/*
(主要是【tab】键,命令补齐、文件名补齐、命令的选项和参数补齐等功能)
(2)个人配置:主要读取~/.bash_profile
在bash读完了整体环境设置的/etc/profile并借此调用其他配置文件后,接下来会读取用户的个人配置文件(其实只会依序读取下面3个文件中的1个,如果第一个不存在才去读取第二个)
~/.bash_profile
、~/.bash_login
、~/.profile
真正的调用可能是:
~/.bash_profile
——~/.bashrc
——/etc/bashrc
[dj@study ~]$ 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/.local/bin:$HOME/bin
export PATH
由于$HOME/bin
在PATH
中,因此,将自己建立的执行文件
放置到自己的家目录下的~/bin/
目录,就可以直接执行该文件,免除输入绝对路径或相对路径的烦恼。
在login shell
环境下,最终被读取的配置文件是~/.bashrc
这个文件。可以将自己的偏好设置写入该文件即可。
(3)source 读入环境配置文件
省的还得注销后再生效,这样可以直接写入shell中。
source configfilename
source ~/.bashrc 将家目录的.bashrc文件读入目前的bash环境中
. ~/.bashrc 同上
10.4.3-2 未输入用户名和密码——进入non-login shell
——
仅会读取~/.bashrc
而已
普通用户的~/.bashrc
:
[dj@study ~]$cat ~/.bashrc
# .bashrc
# Source global definitions
if [ -f /etc/bashrc ]; then
. /etc/bashrc
fi
# Uncomment the following line if you don't like systemctl's auto-paging feature:
# export SYSTEMD_PAGER=
# User specific aliases and functions
root用户的~/.bashrc
:
[root@study ~]# 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
这里,root用户,会继续调用/etc/bashrc
文件,这个/etc/bashrc
文件是RedHat系统特有的。
10.4.3-3 其他可能会影响bash操作的配置文件
(1)/etc/man_db.conf
文件——规定了执行man的时候,该去哪里查看数据的路径设置。
如果以tarball
方式安装软件,man page可能会放置在/usr/local/softpackage/man
,其中softpackage
是软件名称,应手动将该路径添加到/etc/man_db.conf
文件。
(2)~/.bash_history
文件——记录了历史命令。
每次登录bash后,会先读取这个文件,将所有历史命令读入内存。
(3)~/.bash_logout
文件——记录了【当我注销bash后,系统再帮我做完什么操作后才离开】。
默认情况下,注销时,bash只是帮我们清屏。可以自行加入备份或其他重要任务。
10.4.4 终端的环境设置:stty、set
stty -a 查看目前环境中的按键列表
speed 38400 baud; rows 31; columns 138; line = 0;
intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = M-^?; eol2 = M-^?; swtch = M-^?; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R;
werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0;
-parenb -parodd -cmspar cs8 hupcl -cstopb cread -clocal -crtscts
-ignbrk brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl ixon -ixoff -iuclc ixany imaxbel iutf8
opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0
isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
如果不小心在vim中按了 Ctrl + c
,界面锁死,可以按Ctrl + q
解锁。
组合按键 | 执行结果 |
---|---|
Ctrl + c | 终止目前的命令 |
Ctrl + d | 输入结束(EOF) |
Ctrl + m | 回车 |
Ctrl + s | 暂停屏幕输出 |
Ctrl + q | 恢复屏幕输出 |
Ctrl + u | 在提示字符下,将整列命令删除 |
Ctrl + z | 暂停目前的命令 |
10.4.5 通配符与特殊符号
通配符 | 意义 |
---|---|
* | 0个到无穷多个任意字符 |
? | 一定有一个任意字符 |
[] | 一定有一个在括号内的字符(非任意字符)。如[abc]表示一定有一个字符,可能是a,b,c中的任何1个 |
[-] | 在编码顺序内的所有字符。[0-9]表示0-9之间的所有数字,因为数字的语系编码是连续的 |
[^] | 反向选择。[^abc]表示一定有一个字符,只要是非a,b,c的其他字符就接受 |
特殊符号 | 意义 |
---|---|
# | 注释 |
\ | 转义符 |
| | 管道(pipe) |
; | 连续命令执行符 |
$ | 使用变量前导符 |
& | 任务管理,将命令变成后台任务 |
! | 非 |
/ | 目录分隔符 |
> 、>> | 数据流重定向:输出定向,>是替换,>>是累加 |
<、<< | 数据流重定向:输入定向 |
‘’ | 单引号,不具有变量替换功能($为纯文本) |
“” | 双引号,具有变量替换功能 |
`` | 中间为可以先执行的命令,也可以使用$() |
() | 中间为子shell的起始和结束 |
{} | 中间为命令区块的组合 |
10.5 数据流重定向
数据流重定向就是将数据给定向到其他地方去。
数据流重定向就是将某个命令执行后应该要出现在屏幕上的数据,给它传输到其他地方去,如文件或打印机设备。
名称 | 缩写 | 代码 | 传送所用的特殊字符 |
---|---|---|---|
标准输入 | stdin | 0 | < 、 <<(<会覆盖已有的文件,而<<则追加) |
标准输出 | stdout | 1 | > 、 >> |
标准错误输出 | stderr | 2 | 2> 、 2>> |
find /home -name .bashrc > list_right 2> list_error 将正确的输出输出到list_right,错误的输出到list_error
find /home -name .bashrc > list 2>&1 不管错误还是正确,都输出到list文件中
find /home -name .bashrc &> list 同上,不管错误还是正确,都输出到list文件中
<就是,将原本需要由键盘输入的数据,改由文件内容来替换。
[dj@study ~]$ cat > catfile 等键盘输入数据,并按Ctrl+d停止
testing
cat file test
[dj@study ~]$ cat catfile 显示这个得到的文件
testing
cat file test
现在将文件作为来源:
[dj@study ~]$ cat > catfile < ~/.bashrc
[dj@study ~]$ ll catfile ~/.bashrc
-rw-rw-r--. 1 dj dj 231 6月 6 19:12 catfile
-rw-r--r--. 1 dj dj 231 8月 8 2019 /home/dj/.bashrc
[dj@study ~]$ cat > catfile << "eof" 当输入eof的时候会自动终止输入
> This is a test just
> i donot know what to say
> eof
[dj@study ~]$ cat catfile 查看catfile文件
This is a test just
i donot know what to say
[dj@study ~]$ echo "error message" 1>&2 将正常的输出信息重定位到非正常中去,所以会输出
error message
[dj@study ~]$ echo "error message" 2> /dev/null 1>&2 将非正常输出的信息扔到垃圾桶中,将正常输出的信息重定位到非正常输出中去
[dj@study ~]$ cat /dev/null 仍旧nothing
[dj@study ~]$
10.5.2 命令执行的判断依据: ; && ||
前后命令无逻辑关系:用分号
前后命令有逻辑关系:用&&或者||
若前一个命令执行的结果为正确,在Linux下回返回一个$?=0的值。
这个&& 和|| 并非C++里的短路原则!!!
短路原则说的是:
a && b,如果 a为false,直接返回false;如果a为true,才进行b的检查,如果b为false,仍然返回false;
a || b,如果 a为true,直接返回true;如果a为false,才进行b的检查,只要b为true,仍然返回true;
而这里的 && 和||:
在含义上和C++语言中一致,但是在数值上,不一致!
a && b,如果a正确执行(返回0),才会执行b;如果a执行错误(返回非0),b命令不执行。
a || b,如果a正确执行(返回0),不会执行b;如果a执行错误(返回非0),b命令才会执行。
[dj@study ~]$ ls /tmp/test && touch /tmp/test/test.txt 如果这个目录存在,那么在其下创建文件;否则不创建文件
ls: 无法访问/tmp/test: 没有那个文件或目录
[dj@study ~]$ mkdir /tmp/test 创建了这个目录
[dj@study ~]$ ls /tmp/test && touch /tmp/test/test.txt 再次执行上面的命令,这时候就不报错了
[dj@study ~]$ ls /tmp/test 命令执行成功
test.txt
[dj@study ~]$ rm -r /tmp/test 先删除目录
[dj@study ~]$ ls /tmp/test || mkdir /tmp/test 判断目录是否存在,若不存在就创建
ls: 无法访问/tmp/test: 没有那个文件或目录 报错了,果然不存在
[dj@study ~]$ ll -d /tmp/test 但是,这时候也已经被新建好了
drwxrwxr-x. 2 dj dj 6 6月 6 19:53 /tmp/test
[dj@study ~]$ rm -r /tmp/test
[dj@study ~]$ ls /tmp/test || mkdir /tmp/test && touch /tmp/test/abc.txt
ls: 无法访问/tmp/test: 没有那个文件或目录
[dj@study ~]$ ll /tmp/test/abc.txt
-rw-rw-r--. 1 dj dj 0 6月 6 20:00 /tmp/test/abc.txt
command1 && command2 || command3
如果command1执行成功,那么执行command2,command2肯定成功;那么不需执行command3
如果command1执行失败,那么不执行command2;前面执行失败了,去执行command3
10.6 管道命令
less、more、head、tail
(1)管道命令仅处理标准输出,对于标准错误会予以忽略;(通过 2>&1
,使得2>
变成1>
,强行让标准错误可以被管道命令使用)
(2)管道命令必须要能够接受来自前一个命令的数据成为标准输入继续处理才行。
10.6.1 cut 和 grep
[dj@study ~]$ echo ${PATH}
/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/home/dj/.local/bin:/home/dj/bin
[dj@study ~]$ echo ${PATH} | cut -d ':' -f 5 以:为分隔符,从中选取第5段内容
/bin
[dj@study ~]$ echo ${PATH} | cut -d ':' -f 3,5 以:为分隔符,从中选取第3、5两段内容
/usr/bin:/bin
export | cut -c 12-20 这是将export输出的内容,截取每行12-20的字符
grep [-acinv] [--color=auto] '查找字符串' filename
-a 将二进制文件以文本文件的方式查找数据
-c 计算找到‘查找字符’的次数
-i 忽略大小写,大小写视为相同
-n 顺便输出行号
-v 反向选择,显示出没有‘查找字符’内容的那一行
--color=auto 可以将找到的关键字部分加上颜色的显示
显示全部登录信息:
[dj@study ~]$ last
dj pts/0 :0 Sat Jun 6 20:43 still logged in
dj :0 :0 Sat Jun 6 20:42 still logged in
reboot system boot 3.10.0-1062.el7. Sat Jun 6 20:41 - 20:56 (00:15)
dj pts/0 :0 Sat Jun 6 10:04 - 20:40 (10:36)
dj pts/0 :0 Sat Jun 6 09:19 - 10:04 (00:44)
dj :0 :0 Sat Jun 6 09:19 - down (11:21)
reboot system boot 3.10.0-1062.el7. Sat Jun 6 09:17 - 20:40 (11:22)
dj pts/1 :1 Sun May 31 20:29 - 23:20 (02:50)
dj :1 :1 Sun May 31 20:26 - down (02:54)
root pts/0 :0 Sun May 31 19:52 - 23:20 (03:28)
root :0 :0 Sun May 31 19:51 - down (03:29)
reboot system boot 3.10.0-1062.el7. Sun May 31 19:49 - 23:21 (03:31)
dj pts/0 :0 Sun May 31 14:12 - 19:48 (05:35)
dj :0 :0 Sun May 31 14:11 - crash (05:38)
reboot system boot 3.10.0-1062.el7. Sun May 31 14:10 - 23:21 (09:10)
dj pts/0 :0 Sat May 30 15:32 - 18:07 (02:34)
dj :0 :0 Sat May 30 15:23 - down (02:44)
reboot system boot 3.10.0-1062.el7. Sat May 30 15:22 - 18:08 (02:45)
dj pts/0 :0 Sat May 30 11:22 - 15:22 (03:59)
dj :0 :0 Sat May 30 11:21 - crash (04:00)
reboot system boot 3.10.0-1062.el7. Sat May 30 11:20 - 18:08 (06:47)
dj pts/0 :0 Tue May 26 15:30 - 09:10 (17:40)
dj :0 :0 Tue May 26 15:29 - 09:11 (17:41)
reboot system boot 3.10.0-1062.el7. Tue May 26 15:28 - 09:11 (17:42)
dj pts/0 :0 Mon May 25 17:21 - 19:20 (01:59)
dj :0 :0 Mon May 25 17:20 - 19:20 (02:00)
reboot system boot 3.10.0-1062.el7. Mon May 25 17:19 - 19:21 (02:01)
dj pts/0 :0 Thu May 14 17:08 - 22:11 (05:02)
dj :0 :0 Thu May 14 17:08 - crash (11+00:11)
reboot system boot 3.10.0-1062.el7. Thu May 14 17:07 - 19:21 (11+02:13)
dj pts/0 :0 Wed May 13 22:02 - 22:05 (00:02)
dj pts/0 :0 Wed May 13 21:39 - 22:00 (00:20)
dj pts/0 :0 Wed May 13 21:35 - 21:35 (00:00)
dj :0 :0 Wed May 13 21:31 - crash (19:35)
reboot system boot 3.10.0-1062.el7. Wed May 13 21:30 - 19:21 (11+21:50)
dj tty2 Tue May 12 21:43 - 22:11 (00:28)
dj pts/0 :0 Tue May 12 21:22 - 21:24 (00:02)
dj :0 :0 Tue May 12 21:15 - crash (1+00:15)
reboot system boot 3.10.0-1062.el7. Tue May 12 21:14 - 19:21 (12+22:06)
dj :0 :0 Tue May 12 20:30 - crash (00:44)
reboot system boot 3.10.0-1062.el7. Tue May 12 20:29 - 19:21 (12+22:51)
dj pts/0 :0 Fri May 1 21:14 - 21:14 (00:00)
dj pts/0 :0 Wed Apr 29 21:46 - 08:02 (10:16)
dj :0 :0 Wed Apr 29 21:45 - down (12+22:43)
reboot system boot 3.10.0-1062.el7. Wed Apr 29 21:43 - 20:28 (12+22:44)
wtmp begins Wed Apr 29 21:43:52 2020
正向选择,只选包含root的:
[dj@study ~]$ last | grep 'root'
root pts/0 :0 Sun May 31 19:52 - 23:20 (03:28)
root :0 :0 Sun May 31 19:51 - down (03:29)
反向选择,只选不含root的:
[dj@study ~]$ last | grep -v 'root'
dj pts/0 :0 Sat Jun 6 20:43 still logged in
dj :0 :0 Sat Jun 6 20:42 still logged in
reboot system boot 3.10.0-1062.el7. Sat Jun 6 20:41 - 20:56 (00:15)
dj pts/0 :0 Sat Jun 6 10:04 - 20:40 (10:36)
dj pts/0 :0 Sat Jun 6 09:19 - 10:04 (00:44)
dj :0 :0 Sat Jun 6 09:19 - down (11:21)
reboot system boot 3.10.0-1062.el7. Sat Jun 6 09:17 - 20:40 (11:22)
dj pts/1 :1 Sun May 31 20:29 - 23:20 (02:50)
dj :1 :1 Sun May 31 20:26 - down (02:54)
reboot system boot 3.10.0-1062.el7. Sun May 31 19:49 - 23:21 (03:31)
dj pts/0 :0 Sun May 31 14:12 - 19:48 (05:35)
dj :0 :0 Sun May 31 14:11 - crash (05:38)
reboot system boot 3.10.0-1062.el7. Sun May 31 14:10 - 23:21 (09:10)
dj pts/0 :0 Sat May 30 15:32 - 18:07 (02:34)
dj :0 :0 Sat May 30 15:23 - down (02:44)
reboot system boot 3.10.0-1062.el7. Sat May 30 15:22 - 18:08 (02:45)
dj pts/0 :0 Sat May 30 11:22 - 15:22 (03:59)
dj :0 :0 Sat May 30 11:21 - crash (04:00)
reboot system boot 3.10.0-1062.el7. Sat May 30 11:20 - 18:08 (06:47)
dj pts/0 :0 Tue May 26 15:30 - 09:10 (17:40)
dj :0 :0 Tue May 26 15:29 - 09:11 (17:41)
reboot system boot 3.10.0-1062.el7. Tue May 26 15:28 - 09:11 (17:42)
dj pts/0 :0 Mon May 25 17:21 - 19:20 (01:59)
dj :0 :0 Mon May 25 17:20 - 19:20 (02:00)
reboot system boot 3.10.0-1062.el7. Mon May 25 17:19 - 19:21 (02:01)
dj pts/0 :0 Thu May 14 17:08 - 22:11 (05:02)
dj :0 :0 Thu May 14 17:08 - crash (11+00:11)
reboot system boot 3.10.0-1062.el7. Thu May 14 17:07 - 19:21 (11+02:13)
dj pts/0 :0 Wed May 13 22:02 - 22:05 (00:02)
dj pts/0 :0 Wed May 13 21:39 - 22:00 (00:20)
dj pts/0 :0 Wed May 13 21:35 - 21:35 (00:00)
dj :0 :0 Wed May 13 21:31 - crash (19:35)
reboot system boot 3.10.0-1062.el7. Wed May 13 21:30 - 19:21 (11+21:50)
dj tty2 Tue May 12 21:43 - 22:11 (00:28)
dj pts/0 :0 Tue May 12 21:22 - 21:24 (00:02)
dj :0 :0 Tue May 12 21:15 - crash (1+00:15)
reboot system boot 3.10.0-1062.el7. Tue May 12 21:14 - 19:21 (12+22:06)
dj :0 :0 Tue May 12 20:30 - crash (00:44)
reboot system boot 3.10.0-1062.el7. Tue May 12 20:29 - 19:21 (12+22:51)
dj pts/0 :0 Fri May 1 21:14 - 21:14 (00:00)
dj pts/0 :0 Wed Apr 29 21:46 - 08:02 (10:16)
dj :0 :0 Wed Apr 29 21:45 - down (12+22:43)
reboot system boot 3.10.0-1062.el7. Wed Apr 29 21:43 - 20:28 (12+22:44)
wtmp begins Wed Apr 29 21:43:52 2020
将root用户的登录信息那一行拿到,用cut取出第一列数据:
[dj@study ~]$ last | grep 'root' | cut -d ' ' -f 1
root
root
[dj@study ~]$ last | grep 'root' | cut -d ' ' -f1 这里的参数-f与数字1中间可以无空格
root
root
读取/etc/man_db.conf文件,找到包含 'MANPATH' 的那些行,并将关键字'MANPATH' 高亮显示:
grep --color=auto 'MANPATH' /etc/man_db.conf
grep 'MANPATH' /etc/man_db.conf 同上
10.6.2 排序命令:sort、wc、uniq
[dj@study ~]$ cat /etc/passwd | sort
abrt:x:173:173::/etc/abrt:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
...
以第三栏来排序:
[dj@study ~]$ cat /etc/passwd | sort -t ':' -k 3
root:x:0:0:root:/root:/bin/bash
dj:x:1000:1000:dj:/home/dj:/bin/bash
...
以数字顺序排序:
[dj@study ~]$ cat /etc/passwd | sort -t ':' -k 3 -n
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
...
显示最近登录的用户名,并按照用户名顺序排序
[dj@study ~]$ last | cut -d ' ' -f1 | sort
dj
dj
...
uniq [-ic]
-i 忽略大小写字符的不同
-c 进行计数
last | cut -d ' ' -f1 | sort |uniq 排序后,将重复的内容只显示一个:
输出:
dj
reboot
root
wtmp
last | cut -d ' ' -f1 | sort |uniq -c 排序后,将重复的内容只显示一个,且统计每个出现的总次数
输出:
30 dj
13 reboot
2 root
1 wtmp
wc [-lwm]
-l 仅列出行
-w 仅列出多少字(英文字母)
-m 多少字符
cat /etc/man_db.conf | wc 统计该文件中有多少内容
输出:
131 723 5171 行、字数、字符数
一行命令取得登录系统的总人次,将那些不对的内容过滤掉,统计对的行数即可:
last | grep [a-zA-Z] | grep -v 'wtmp' | grep -v 'reboot' | grep -v 'unknown' | wc -l
输出:
32
查看当前账号文件中有多少个账号:
cat /etc/passwd | wc -l
10.6.3 双向重定向:tee
tee可以让标准输出转存一份到文件,并将同样的数据继续输送到屏幕上去处理。
tee [-a] filename
-a 以累加方式将数据添加进filename,而非覆盖
last | tee last.list | cut -d " " -f1 将last的信息同时保存一份到last.list文件了
last | cut -d " " -f1 | tee last.list 将cut处理后的内容保存一份到last.list
10.6.4 字符转换命令:tr、col、join、paste、expand
tr [-ds] SET1 ...
-d 删除信息中的SET1这个字符
-s 替换掉重复的字符
last | tr '[a-z]' '[A-Z]' 将last中的小写字符都换成大写字符
last | tr [a-z] [A-Z] 同上
cat /etc/passwd | tr -d ':' 删除每行的冒号
col [-xb]
-x 将tab键转换成对等的空格键
cat -A /etc/man_db.conf 显示tab键^I
cat /etc/man_db.conf | col -x | cat -A | more 替换为空格键并显示
join [-ti11] [-ti12] file1 file2 使用之前应该先排序
-t 默认以空格字符分隔数据,并且比对第一个栏位的数据,如果相同,就合并
-i 忽略大小写
-1 这个是数字的1,第一个文件要用哪个栏位来分析
-2 同上
join -t ':' /etc/passwd /etc/shadow | head -n 3 将前3行以:为分隔符的两各文件合并
join -t ':' -1 4 /etc/passwd -2 3 /etc/group | head -n 3 文件1以第4栏,文件2以第3栏比较
paste [-d] file1 file2
-d 后面可以接分隔符,默认分隔符是tab键
- 如果file部分写成-,表示来自标准输入的数据
paste /etc/passwd /etc/shadow
cat /etc/group | paste /etc/passwd /etc/shadow - | head -n 3 将3个文件粘贴到一起,只看前三行
expand [-t] filename 自动将Tab键转换成空格键
-t 接数字,让一个tab键代表多少个字符,默认是8个字符
grep '^MANPATH' /etc/man_db.conf | head -n 3 | expand -t 8 -| cat -A
10.6.5 划分命令:split
split [-bl] file PREFIX
-b 后接欲划分成的文件大小,可加单位,b,k,m等
-l 以行数来划分
PREFIX 前缀字符
split -b 300k /etc/services services
ll -k services*
输出:
-rw-r--r--. 1 root root 307200 6月 6 22:25 servicesaa
-rw-r--r--. 1 root root 307200 6月 6 22:25 servicesab
-rw-r--r--. 1 root root 55893 6月 6 22:25 servicesac
cat servicesa* >> servicesback
ll -k services*
输出:
-rw-r--r--. 1 root root 307200 6月 6 22:25 servicesaa
-rw-r--r--. 1 root root 307200 6月 6 22:25 servicesab
-rw-r--r--. 1 root root 55893 6月 6 22:25 servicesac
-rw-r--r--. 1 root root 670293 6月 6 22:26 servicesback
ls -al / | split -l 10 - lsroot
wc -l lsroot*
输出:
10 lsrootaa
10 lsrootab
4 lsrootac
24 总用量
10.6.6 参数代换:xargs
[dj@study ~]$ 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)
加上-p会询问是否进行id操作:
[dj@study ~]$ 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)
如果分析到'sync'就停止操作,-e与'sync'中间没有空格:
cut -d ':' -f 1 /etc/passwd | head -n 3 | xargs -e'sync' -n 1 id
很多命令不支持管道命令,可以通过xargs来提供该命令使用标准输入。
找出/usr/sbin中具有特殊权限的文件名:
find /usr/sbin -perm /7000 | xargs ls -l
ls -l $(find /usr/sbin -perm /7000)
10.6.7 关于减号-的用途
tar -cvf - /home | tar -xvf - -C /tmp/homeback
这里解释如下:
先把/home下的数据打包到标准输出(-)
再把该标准输出(-)通过管道(|)传输到后面,作为解压缩的标准输入(-)
可以省略文件名