硬件、内核和Shell
在计算机系统重,Shell是一个很常见的词汇,甚至很多软件就以shell命名。比如微软的PowerShell等。那到底什么是shell呢。
首先我们的电脑操作系统其实是一组软件,用户通过这些软件来操作电脑上的硬件。我们通过shell将命令输入给操作系统,操作系统与内核进行沟通,最终去调动我们想操作的硬件。
这样一来,shell就是在整个系统的最外层,像一个壳一样保护着系统的内核。
为什么要学习shell
首先,Linux系统虽然也有桌面操作系统,但是一般为了服务器的效率和轻量化,只会安装Linux的核心程序,大多数情况下我们需要用shell和系统进行交互。
其次,一些复杂的操作,和一些软件的设置,也确实需要通过shell。
Bash shell的功能
shell曾经有很多版本,不过现在默认用的是/bin/bash,它有很多很棒的功能。
-
记录历史命令:通过键盘上的↑↓键,我们可以很轻松的翻看之前执行过的命令,这是一个很实用的功能
-
命令与文件补全:tab键可以补全命令和文件名
-
命令别名设置alisa:可以输入alias看看默认有哪些设置,这个功能类似于python里的import pandas as pd
python[root@node4 ~]# alias alias cp='cp -i' alias egrep='egrep --color=auto' alias fgrep='fgrep --color=auto' alias grep='grep --color=auto' ...
-
支持通配符和脚本编程
查看bash命令type
通过type可以查看某个命令是否是bash内置的
python
[root@node4 ~]# type -a ls
ls 是 `ls --color=auto' 的别名
ls 是 /usr/bin/ls
Shell中的变量
举例来说,用户a的邮件存储在/var/spool/mail/usera,用户b登录系统后,他的邮件存储在/var/spool/mail/userb。在使用mail命令收发邮件时,它自动会替换变量为用户名,就不会出现a的邮件和b混在一起的情况了
环境变量PATH,这个前面了解过了。我们之所以能在各个路径下执行系统命令,就是因为这个PATH
-
使用echo查看变量:
python[root@node4 ~]# echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/usr/java/default/bin:/usr/java/default/bin:/opt/zookeeper-3.4.6/bin:/opt/hadoop-2.6.5/bin:/opt/hadoop-2.6.5/sbin:/opt/nginx/sbin:/root/bin [root@node4 ~]# echo $HOME /root
-
使用echo设定变量:
python# myname还未赋值 [root@node4 ~]# echo $myname # 赋值过程,注意不能有空格 [root@node4 ~]# myname=kayotin # 赋值后 [root@node4 ~]# echo $myname kayotin
-
双引号中的特殊字符可以保有原始特效
python[root@node4 ~]# myvar="lang is $LANG" [root@node4 ~]# echo $myvar lang is zh_CN.UTF-8
-
单引号中的字符是纯文本
python[root@node4 ~]# myvar='lang is $LANG' [root@node4 ~]# echo $myvar lang is $LANG
-
取消变量内容
python[root@node4 ~]# unset myvar
环境变量的功能
用env命令可以看到当前的环境变量:
python
[root@node4 ~]# env
XDG_SESSION_ID=1
HOSTNAME=node4
TERM=xterm
SHELL=/bin/bash
HADOOP_HOME=/opt/hadoop-2.6.5
HISTSIZE=1000
SSH_CLIENT=192.168.32.1 10043 22
SSH_TTY=/dev/pts/0
USER=root
......
set命令可以显示所有变量,包括我们自己设置的
python
[root@node4 ~]# set
BASH=/bin/bash
......
colors=/root/.dircolors
myname=kayotin
**$**本身也是一个变量,代表当前shell的pid
python
[root@node4 ~]# echo $$
1974
?也是一个变量,代表上一个指令的执行结果
python
# 代表上一个指令执行成功
[root@node4 ~]# echo $?
0
[root@node4 ~]# 12name=123
-bash: 12name=123: 未找到命令
# 上一个命令执行错误,返回错误代码
[root@node4 ~]# echo $?
127
从键盘输入变量read
通过read命令,我们将输入内容作为赋值给了变量atest。read命令常用来做用户输入,有点像python的input方法。
python
[root@node4 ~]# read atest
this is a test
[root@node4 ~]# echo $atest
this is a test
声明变量类型declare,typeset
declare和typeset这两个命令用来声明变量的类型,如下例子
python
# 默认是字符串
[root@node4 ~]# sum=100+200
[root@node4 ~]# echo $sum
100+200
# 声明sum是int类型后,就能正确计算结果了
[root@node4 ~]# declare -i sum=100+200
[root@node4 ~]# echo $sum
300
# 常用参数
-i 指定为int
-a 定义为数组类型
-x 与export类似,将变量定义为环境变量
-r 将变量定义为只读,值不可修改
数组
python
[root@node4 ~]# my_arr[1]=alice
[root@node4 ~]# echo ${my_arr[1]}
alice
[root@node4 ~]# my_arr[2]=giri
[root@node4 ~]# echo ${my_arr[2]}
giri
文件系统限制-ulimit
为了防止多人登录时,系统加载太多资源挂掉,可以用ulimit命令设置一些限制
python
# 打印当前设置
[root@node4 ~]# ulimit -a
core file size (blocks, -c) 0
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
变量的删除替换操作
#符合替换文字【最短的】一个
##符合替换文字【最长的】那一个
python
[root@node4 ~]# echo ${MAIL##/*/}
root
[root@node4 ~]# echo ${MAIL%/*}
/var/spool/mail
历史命令history
前面说过,linux默认最多记录1000个历史命令,通过history就可以看到这些历史命令
python
[root@node4 ~]# history
1 vi /etc/hosts
2 date
3 vim /etc/hosts
4 vim /etc/profile
5 chkconfig
......
数据流向>
python
# 将ll打印的信息,输出到myfile这个文件里
[root@node4 ~]# ll > myfile
[root@node4 ~]# ls
anaconda-ks.cfg backups hello.txt myfile newfile newslink zookeeper.out
[root@node4 ~]# cat myfile
- 1>:默认方式,以覆盖方式将正确数据输出到指定文件或设备
- 1>>:以累加方式将正确数据输出到指定文件或设备
- 2>:以覆盖方式将错误数据输出到指定文件或设备
- 2>>:以累加方式将错误数据输出到指定文件或设备
python
# 将键盘输入数据增量保存在刚刚的myfile
[root@node4 ~]# cat >> myfile
ceshi ceshi ceshi
[root@node4 ~]# cat myfile
总用量 28
-rw-------. 1 root root 1338 6月 25 2022 anaconda-ks.cfg
drwx------ 2 root root 6 3月 31 17:32 backups
-rw-r--r-- 1 root root 7 4月 8 20:10 hello.txt
-rw-r--r-- 1 root root 0 4月 10 20:29 myfile
-rw-r--r-- 2 root root 0 3月 28 21:00 newfile
lrwxrwxrwx 1 root root 12 3月 28 21:10 newslink -> /opt/newfile
-rw-r--r-- 1 root root 19489 11月 9 2022 zookeeper.out
ceshi ceshi ceshi
可以使用反向的<和<<从文件读取数据
如果想要保存到文件的同时在屏幕上输出,可以使用tee命令
一次执行多个命令; && ||
想要在一次输入后,执行多个命令,有以下几种方式
-
命令;命令:此种方式不考虑多个命令之间的关联性,也就是不管前面的命令是成功或者失败,都会继续执行,例如
pythonsync; shutdown -h now
-
命令1&&命令2:如果命令1正确执行(也就是读取到$?=0),才会执行命令2;否则不执行命令2
python[root@node4 ~]# ls testfile && touch testfile ls: 无法访问testfile: 没有那个文件或目录
-
命令1||命令2:如果命令1正确执行,那就不执行命令2;否则执行命令2
python# 可以看到虽然报错了,但这个file已经建立了,也就是命令2执行了 [root@node4 ~]# ls testfile || touch testfile ls: 无法访问testfile: 没有那个文件或目录 [root@node4 ~]# ll testfile -rw-r--r-- 1 root root 0 4月 10 20:56 testfile
管道命令|和选取命令:cut、grep
有时候我们需要命令1的结果去作为命令2的输入,这时候就要用管道命令。
也正因为如此,它常常和切片命令cut、grep一起使用,因为往往前一个命令的输出只有一部分是我们需要的。
-
cut命令对输入字符进行切片
python# 以:分隔,输出第一个结果 [root@node4 ~]# echo $PATH | cut -d ':' -f 1 /usr/local/sbin # 支持多个,比如输入1和3 [root@node4 ~]# echo $PATH | cut -d ':' -f 1,3 /usr/local/sbin:/usr/sbin # 切片,保留[12:] [root@node4 ~]# export declare -x HADOOP_HOME="/opt/hadoop-2.6.5" declare -x HISTCONTROL="ignoredups" [root@node4 ~]# export | cut -c 12- HADOOP_HOME="/opt/hadoop-2.6.5" HISTCONTROL="ignoredups"
-
grep分析一行信息,如果有我们需要的,就拿出来,有点像筛选
python# 筛选包含root的行 [root@node4 ~]# last | grep root root pts/0 192.168.32.1 Wed Apr 10 19:37 still logged in root pts/0 192.168.32.1 Tue Apr 9 20:56 - down (01:01) # 不包含root的行 [root@node4 ~]# last | grep -v root reboot system boot 3.10.0-1160.108. Wed Apr 10 19:34 - 21:10 (01:35) reboot system boot 3.10.0-1160.108. Tue Apr 9 20:42 - 21:57 (01:14)
排序命令:sort、wc、uniq
-
使用sort进行排序
python# 对用户信息按字母顺序排序 [root@node4 ~]# 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
-
uniq,进行重复
python# uniq不显示重复数据 [root@node4 ~]# last | cut -d ' ' -f1 | sort | uniq reboot root wtmp # 统计每个用户登录次数 [root@node4 ~]# last | cut -d ' ' -f1 | sort | uniq -c 1 40 reboot 42 root 1 wtmp
-
wc:统计字数
python[root@node4 ~]# last | wc 84 865 6352 # 分别代表行 字数 字符数 # 计算历史登录总人数 [root@node4 ~]# last | grep [a-zA-Z] | grep -v 'reboot'| wc -l 43
字符转换命令 tr/col/join/paste/expand
-
tr
python# 替换成大写 [root@node4 ~]# last | tr '[a-z]' '[A-z]' ROOT PTS/0 192.168.32.1 WED APR 10 19:37 STILL LOGGED IN
-
col 多用来将tab替换为空格
python[root@node4 ~]# cat /etc/man_db.conf | col -x | cat -A |more
-
join处理相关数据
python# 比如passwd和shadow这两个文件,他们的签名都是用户名 [root@node4 ~]# 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$Rj7coYh/STyMcxjn$ZY.l1SDPcsJv1NUwiA.INYB7Q/bTxAXHFyRTm42M/qxdPWAt9Ly3eQSpu1Xn5v9LkxLJITwb6igAUPMOD.mBj/::0:99999:7::: bin:*:18353:0:99999:7::: daemon:*:18353:0:99999:7::: # 将相同用户名数据拼起来 [root@node4 ~]# join -t ':' /etc/passwd /etc/shadow | head -n 3 root:x:0:0:root:/root:/bin/bash:$6$Rj7coYh/STyMcxjn$ZY.l1SDPcsJv1NUwiA.INYB7Q/bTxAXHFyRTm42M/qxdPWAt9Ly3eQSpu1Xn5v9LkxLJITwb6igAUPMOD.mBj/::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:::
-
paste 直接将两行粘在一起,中间用tab分隔
python[root@node4 ~]# paste /etc/passwd /etc/shadow root:x:0:0:root:/root:/bin/bash root:$6$Rj7coYh/STyMcxjn$ZY.l1SDPcsJv1NUwiA.INYB7Q/bTxAXHFyRTm42M/qxdPWAt9Ly3eQSpu1Xn5v9LkxLJITwb6igAUPMOD.mBj/::0:99999:7:::
-
expand也是转换tab为空格