shell基础知识(shell入门)二

1、shell简介
2、变量类型:事先确定数据的存储格式和长度
3、grep, egrep, fgrep
4、逻辑运算符
5、bash变量类型
6、条件判断
7、shell中进行算术运算:
8、文件测试
9、参数传递

一、shell简介
编译器,解释器
编程语言:机器语言、汇编语言、高级语言
静态语言:编译型语言
强类型(变量)
事先转换成可执行格式
C、C++、JAVA、C#
动态语言:解释型语言, on the fly
弱类型
边解释边执行
PHP、SHELL、python、perl

面向过程:Shell, C dev ops
面向对象: JAVA, Python, perl, C++

变量:内存空间,命名
内存:编址的存储单元

shell: 外壳
GUI:Gnome, KDE, Xfce
CLI: sh, csh, ksh, bash, tcsh, zsh

登录式shell如何读取配置文件?
/etc/profile –> /etc/profile.d/*.sh –> ~/.bash_profile –> ~/.bashrc –> /etc/bashrck
Source /etc/bashrc

非登录式shell如何配置文件?
~/.bashrc –> /etc/basrc –> /etc/profile.d/*.sh

https://blog.csdn.net/a491057947/article/details/38386923

二、变量类型:事先确定数据的存储格式和长度
字符
数值
整型
浮点型: 11.23, 1.123*10^1, 0.1123*10^2
2013/10/10, 64bit
99999: 24bit,
真、假
命令替换: $(COMMAND), 反引号COMMAND
把命令中某个子命令替换为其执行结果的过程
file-2013-02-28-14-53-31.txt

bash支持的引号:

``: 命令替换
"": 强引用,可以实现变量替换
'': 弱引用,不完成变量替换
文件名通配, globbing
*: 任意长度的任意字符
?:任意单个字符
[ ]:匹配指定范围内的任意单个字符
    [abc], [a-m], [a-z], [A-Z], [0-9], [a-zA-Z], [0-9a-zA-Z]
    [:space:]:空白字符
    [:punct:]:标点符号
    [:lower:]:小写字母
    [:upper:]: 大写字母
    [:alpha:]: 大小写字母
    [:digit:]: 数字
    [:alnum:]: 数字和大小写字母 
[^]: 匹配指定范围之外的任意单个字符
[[:alpha:]]*[[:space:]]*[^[:alpha:]]

练习:
1、创建a123, cd6, c78m, c1 my, m.z, k 67, 8yu, 789等文件;注意,以上文件是以逗号隔开的,其它符号都是文件名的组成部分;
2、显示所有以a或m开头的文件;
ls [am]*
3、显示所有文件名中包含了数字的文件;
ls [0-9]
ls [[:digit:]]
4、显示所有以数字结尾且文件名中不包含空白的文件;
ls [^[:space:]][0-9] ?????????
5、显示文件名中包含了非字母或数字的特殊符号的文件;
ls [^[:alnum:]]

三、grep, egrep, fgrep
grep: 根据模式搜索文本,并将符合模式的文本行显示出来。
pattern: 文本字符和正则表达式的元字符组合而成匹配条件
grep [options] PATTERN [FILE…]

     -c :只显示匹配行的数量
          -i : 忽略大小写
         -n : 打印行号
         -s :静默工作,不显示错误信息
         -q :静默工作,不显示查找结果
         -v :只显示不匹配的行
        -w :等效于< >
        -o:只显示被模式匹配到的字符串    
        -E: 使用扩展正则表达式  
        -A #: 显示匹配行和之后的几行
        -B #: grep -i -B 2 root /etc/passwd 
        -C #:计算匹配项的数目

**正则表达式:**REGular EXPression, REGEXP
Basic REGEXP:基本
Extended REGEXP:扩展

元字符:
“.” 匹配任意单个字符
[]: 匹配指定范围内的任意单个字符
[^]:匹配指定范围外的任意单个字符
字符集合:[:digit:], [:lower:], [:upper:], [:punct:], [:space:], [:alpha:], [:alnum:]

匹配次数(贪婪模式)
*: 匹配其前面的字符任意次
a, b, ab, aab, acb, adb, amnb
a*b, a\?b
a.*b

.*: 任意长度的任意字符
\?: 匹配其前面的字符1次或0次
{m,n}:匹配其前面的字符至少m次,至多n次
{1,}
{0,3}

位置锚定:
^: 锚定行首,此字符后面的任意内容必须出现在行首
: 锚定行尾,此字符前面的任意内容必须出现在行尾  
^
: 锚定行尾,此字符前面的任意内容必须出现在行尾  ^
: 空白行

\<或\b: 锚定词首,其后面的任意字符必须作为单词首部出现
>或\b: 锚定词尾,其前面的任意字符必须作为单词的尾部出现

分组:
()
(ab)*
后向引用
\1: 引用第一个左括号以及与之对应的右括号所包括的所有内容
\2:
\3:
He love his lover.
She like her liker.
He like his lover.

练习:
1、显示/proc/meminfo文件中以不区分大小的s开头的行;
grep -i ‘^s’ /proc/meminfo
grep ‘^[sS]’ /proc/meminfo
2、显示/etc/passwd中以nologin结尾的行;
grep ‘nologin /etc/passwdshell/sbin/nologingrepnologin ′ / e t c / p a s s w d 取 出 默 认 s h e l l 为 / s b i n / n o l o g i n 的 用 户 列 表 g r e p “ n o l o g i n ’ /etc/passwd | cut -d: -f1
取出默认shell为bash,且其用户ID号最小的用户的用户名
grep ‘bash’ /etc/passwd | sort -n -t: -k3 | head -1 | cut -d: -f1  
3、显示/etc/inittab中以#开头,且后面跟一个或多个空白字符,而后又跟了任意非空白字符的行;  
grep “^#[[:space:]]{1,}[^[:space:]]” /etc/inittab  
4、显示/etc/inittab中包含了:一个数字:(即两个冒号中间一个数字)的行;  
(该文件主要是说明系统是从哪个级别开始启动的‘系统级别  
总共7各级别级别:0 表示关机  
1 单用户模式)  
grep ‘:[0-9]:’ /etc/inittab  
5、显示/boot/grub/grub.conf文件中以一个或多个空白字符开头的行;  
grep ‘^[[:space:]]{1,}’ /boot/grub/grub.conf  
6、显示/etc/inittab文件中以一个数字开头并以一个与开头数字相同的数字结尾的行;  
grep ‘^([0-9]).*\1
’ /etc/passwd | sort -n -t: -k3 | head -1 | cut -d: -f1  3、显示/etc/inittab中以#开头,且后面跟一个或多个空白字符,而后又跟了任意非空白字符的行;  grep “^#[[:space:]]{1,}[^[:space:]]” /etc/inittab  4、显示/etc/inittab中包含了:一个数字:(即两个冒号中间一个数字)的行;  (该文件主要是说明系统是从哪个级别开始启动的‘系统级别  总共7各级别级别:0 表示关机  1 单用户模式)  grep ‘:[0-9]:’ /etc/inittab  5、显示/boot/grub/grub.conf文件中以一个或多个空白字符开头的行;  grep ‘^[[:space:]]{1,}’ /boot/grub/grub.conf  6、显示/etc/inittab文件中以一个数字开头并以一个与开头数字相同的数字结尾的行;  grep ‘^([0-9]).*\1
’ /etc/inittab

练习:
1、找出某文件中的,1位数,或2位数;
grep ‘[0-9]{1,2}’ /proc/cpuinfo
grep –color ‘\<[0-9]{1,2}>’ /proc/cpuinfo
2、找出ifconfig命令结果中的1-255之间的整数;
3、查找当前系统上名字为student(必须出现在行首)的用户的帐号的相关信息, 文件为/etc/passwd
grep ‘^student>’ /etc/passwd | cut -d: -f3
id -u student
student1
student2
练习:分析/etc/inittab文件中如下文本中前两行的特征(每一行中出现在数字必须相同),请写出可以精确找到类似两行的模式:
l1:1:wait:/etc/rc.d/rc 1
l3:3:wait:/etc/rc.d/rc 3
grep ‘^l([0-9]):\1.*\1$’ /etc/inittab

四、逻辑运算符
逻辑:1+1>2
逻辑运算:与、或、非、异或
1: 真
0: 假
1 & 0 = 0
0 & 1 = 0
0 & 0 = 0
1 & 1 = 1
或:
非:
! 真 = 假
! 假 = 真

命令的间逻辑关系:
逻辑与: &&
第一个条件为假时,第二条件不用再判断,最终结果已经有;
第一个条件为真时,第二条件必须得判断;
逻辑或: ||
脚本:命令的堆砌,按实际需要,结合命令流程控制机制实现的源程序
测试脚本是否有语法错误:
bash -n 脚本
bash -x 脚本:单步执行

shebang: 魔数

!/bin/bash

注释行,不执行

/dev/null: 软件设备, bit bucket,数据黑洞
脚本在执行时会启动一个子shell进程;
命令行中启动的脚本会继承当前shell环境变量;
系统自动执行的脚本(非命令行启动)就需要自我定义需要各环境变量;

练习:写一个脚本,完成以下任务
1、添加5个用户, user1,…, user5
2、每个用户的密码同用户名,而且要求,添加密码完成后不显示passwd命令的执行结果信息;
3、每个用户添加完成后,都要显示用户某某已经成功添加;
useradd user1
echo “user1” | passwd –stdin user1 &> /dev/null
echo “Add user1 successfully.”
如果用户存在,就显示用户已存在;否则,就添加此用户;
id user1 && echo “user1 exists.” || useradd user1
如果用户不存在,就添加;否则,显示其已经存在;
! id user1 && useradd user1 || echo “user1 exists.”
如果用户不存在,添加并且给密码;否则,显示其已经存在;

练习,写一个脚本,完成以下要求:
1、添加3个用户user1, user2, user3;但要先判断用户是否存在,不存在而后再添加;
2、添加完成后,显示一共添加了几个用户;当然,不能包括因为事先存在而没有添加的;
3、最后显示当前系统上共有多少个用户;

练习:写一个脚本
判定命令历史中历史命令的总条目是否大于1000;如果大于,则显示“Some command will gone.”;否则显示“OK”。
[ wc -l access.log |cut -d" " -f1 -gt 10 ] && echo “xx”

五、bash变量类型:
环境变量
本地变量(局部变量)
位置变量
特殊变量

变量名称
1、只能包含字母、数字和下划线,并且不能数字开头;
2、不应该跟系统中已有的环境变量重名;
3、最好做到见名知义;

本地变量
set VARNAME=VALUE: 作用域为整个bash进程;
局部变量
local VARNAME=VALUE:作用域为当前代码段;
环境变量:
作用域为当前shell进程及其子进程;
export VARNAME=VALUE
VARNAME=VALUE
export VARNAME
“导出”
位置变量:
1, 1 , 2, …
Shift
特殊变量:
?:02550:125512127 ? : 上 一 个 命 令 的 执 行 状 态 返 回 值 ; 程 序 执 行 , 可 能 有 两 类 返 回 值 : 程 序 执 行 结 果 程 序 状 态 返 回 代 码 ( 0 − 255 ) 0 : 正 确 执 行 1 − 255 : 错 误 执 行 , 1 , 2 , 127 系 统 预 留 ; #
@
$$
$0
输出重定向:
>

>
2>
2>>
&>

撤消变量:
unset VARNAME

查看当shell中变量:
Set (可以省略)
查看当前shell中的环境变量:
printenv
env
export

六、条件判断
bash中如何实现条件判断?
单分支if语句
if 判断条件; then
statement1
statement2

fi

双分支的if语句:
if 判断条件; then
statement1
statement2

else
statement3
statement4

fi

多分支的if语句:
if 判断条件1; then
statement1

elif 判断条件2; then
statement2

elif 判断条件3; then
statement3

else
statement4

fi
条件测试类型:
整数测试
字符测试
文件测试

条件测试的表达式:
[ expression ]
[[ expression ]]
test expression
如果/etc/inittab文件的行数大于100,就显示好大的文件;
[ wc -l /etc/inittab | cut -d' ' -f1 -gt 100 ] && echo “Large file.”

整数比较:
    -eq: 测试两个整数是否相等;比如 $A -eq $B
    -ne: 测试两个整数是否不等;不等,为真;相等,为假;
    -gt: 测试一个数是否大于另一个数;大于,为真;否则,为假;
    -lt: 测试一个数是否小于另一个数;小于,为真;否则,为假;
    -ge: 大于或等于
    -le:小于或等于

练习,写一个脚本,完成以下要求:
给定一个用户:
1、如果其UID为0,就显示此为管理员;
2、否则,就显示其为普通用户;
如果 UID为0;那么
显示为管理员
否则
显示为普通用户

NAME=user16
USERID=id -u $NAME
if [ $USERID -eq 0 ]; then
echo “Admin”
else
echo “common user.”
fi

NAME=user16
if [ id -u $NAME -eq 0 ]; then
echo “Admin”
else
echo “common user.”
fi

练习:写一个脚本
判断当前系统上是否有用户的默认shell为bash;
如果有,就显示有多少个这类用户;否则,就显示没有这类用户;
grep “bash” /etc/passwd &> /dev/null  
RETVAL=
” /etc/passwd &> /dev/null  RETVAL=
?
if [ RETVALeq0];thenifgrepbash R E T V A L − e q 0 ] ; t h e n i f g r e p “ b a s h ” /etc/passwd &> /dev/null; then
提示:“引用”一个命令的执行结果,要使用命令引用;比如: RESAULTS=wc -l /etc/passwd | cut -d: -f1
使用一个命令的执行状态结果,要直接执行此命令,一定不能引用;比如: if id user1一句中的id命令就一定不能加引号;
如果想把一个命令的执行结果赋值给某变量,要使用命令引用,比如USERID=id -u user1;
如果想把一个命令的执行状态结果保存下来,并作为命令执行成功与否的判断条件,则需要先执行此命令,而后引用其状态结果,如
id -u user1
RETVAL=$?
此句绝对不可以写为RETVAL=id -u user1

练习:写一个脚本
判断当前系统上是否有用户的默认shell为bash;
如果有,就显示其中一个的用户名;否则,就显示没有这类用户;
练习:写一个脚本
给定一个文件,比如/etc/inittab
判断这个文件中是否有空白行;
如果有,则显示其空白行数;否则,显示没有空白行。

!/bin/bash

A=grep '^$' /etc/inittab | wc -l
if [ Agt0];thenecho A − g t 0 ] ; t h e n e c h o “ A”
else
echo “meiyoukongbaihang”
fi

!/bin/bash

FILE=/etc/inittab
if [ ! -e FILE];thenechoNo F I L E ] ; t h e n e c h o “ N o FILE.”
exit 8
fi

if grep “^ " " FILE &> /dev/null; then
echo “Total blank lines: grep "^$" $FILE | wc -l.”
else
echo “No blank line.”
fi

练习:写一个脚本
给定一个用户,判断其UID与GID是否一样
如果一样,就显示此用户为“good guy”;否则,就显示此用户为“bad guy”。

!/bin/bash

USERNAME=user1
USERID=id -u $USERNAME
GROUPID=id -g $USERNAME
if [ USERIDeq U S E R I D − e q GROUPID ]; then
echo “Good guy.”
else
echo “Bad guy.”
fi

进一步要求:不使用id命令获得其id号;

!/bin/bash

USERNAME=user1
if ! grep “^$USERNAME>” /etc/passwd &> /dev/null; then

echo “No such user: $USERNAME.”
exit 1
fi

USERID=grep "^$USERNAME\>" /etc/passwd | cut -d: -f3
GROUPID=grep "^$USERNAME\>" /etc/passwd | cut -d: -f4
if [ USERIDeq U S E R I D − e q GROUPID ]; then
echo “Good guy.”
else
echo “Bad guy.”
fi

七、shell中进行算术运算:
A=3
B=6
**1、**let 算术运算表达式
let C= A+ A + B
2、 []C= [ 算 术 运 算 表 达 式 ] C = [ A+ A + B]
3、 (())C= ( ( 算 术 运 算 表 达 式 ) ) C = (( A+ A + B))
**4、**expr 算术运算表达式,表达式中各操作数及运算符之间要有空格,而且要使用命令引用
C=expr $A + $B

练习:写一个脚本
给定一个用户,获取其密码警告期限;
而后判断用户密码使用期限是否已经小于警告期限;
提示:计算方法,最长使用期限减去已经使用的天数即为剩余使用期限;

如果小于,则显示“Warning”;否则,就显示“OK”。

圆整:丢弃小数点后的所有内容

!/bin/bash
W=`grep "student" /etc/shadow | cut -d: -f6`
S=`date +%s`
T=`expr $S/86400`
L=`grep "^student" /etc/shadow | cut -d: -f5`
N=`grep "^student" /etc/shadow | cut -d: -f3`
SY=$[$L-$[$T-$N]]

if [ $SY -lt $W ]; then
  echo 'Warning'
else
  echo 'OK'

八、文件测试:

-e FILE:测试文件是否存在
-f FILE: 测试文件是否为普通文件
-d FILE: 测试指定路径是否为目录
-r FILE: 测试当前用户对指定文件是否有读取权限;
-w FILE:测试当前用户对指定文件是否有写权限;
-x FILE:    测试当前用户对指定文件是否有执行权限;
[ -e /etc/inittab ]
[ -x /etc/rc.d/rc.sysinit ] 

练习:写一个脚本
给定一个文件:
如果是一个普通文件,就显示之;
如果是一个目录,亦显示之;
否则,此为无法识别之文件;

定义脚本退出状态码
exit: 退出脚本
exit #
如果脚本没有明确定义退出状态码,那么,最后执行的一条命令的退出码即为脚本的退出状态码;

九、参数传递
./filetest.sh /etc/fstab /etc/inittab
1:/etc/fstab 1 : / e t c / f s t a b 2: /etc/inittab

练习:写一脚本
能接受一个参数(文件路径)
判定:此参数如果是一个存在的文件,就显示“OK.”;否则就显示”No such file.”
练习:写一个脚本
给脚本传递两个参数(整数);
显示此两者之和,之乘积;

###!/bin/bash
#
if [ $# -lt 2 ]; then
  echo "Usage: cacl.sh ARG1 ARG2"
  exit 8
fi

o “The sum is: [ [ 1+ 2].echoTheprodis: 2 ] . ” e c h o “ T h e p r o d i s : [ 1 1 ∗ 2].”
练习:写一个脚本,完成以下任务
1、使用一个变量保存一个用户名;
2、删除此变量中的用户,并且删除其家目录;
3、显示“用户删除完成”类的信息;

你可能感兴趣的:(shell基础知识(shell入门)二)