Shell 练习题(二)

变量

根据变量的生效范围等标准划分下面变量类型:

  • 局部变量:生效范围为当前shell进程;对当前shell之外的其它shell进程,包括当前shell的子shell进程均无效
  • 环境(全局)变量:生效范围为当前shell进程及其子进程
    变量声明、赋值:export name=VALUE,declare -x name=VALUE
    变量引用:$name, ${name}
    显示所有环境变量:env,printenv,export,declare -x
    删除变量:unset name
  • 本地变量:生效范围为当前shell进程中某代码片断,通常指函数
  • 位置变量:$1, $2, …来表示,用于让脚本在脚本代码中调用通过命令行传递给它的参数
    $1, $2, …:对应第1、第2等参数,shift [n]换位置
    $0: 命令本身
    $: 传递给脚本的所有参数,全部参数合为一个字符串
    $@: 传递给脚本的所有参数,每个参数为独立字符串
    $#: 传递给脚本的参数的个数
    $@ $
    只在被双引号包起来的时候才会有差异
    set – 清空所有位置变量
  • 特殊变量:$?, $0, $*, $@, KaTeX parse error: Expected 'EOF', got '#' at position 1: #̲,$
    $? 变量保存最近的命令退出状态。 0 代表成功,1-255代表失败 echo $?

read

使用read来把输入值分配给一个或多个shell变量
-p 指定要显示的提示
-s 静默输入,一般用于密码
-n N 指定输入的字符长度N -d ‘字符’ 输入结束符
-t N TIMEOUT为N秒
read 从标准输入中读取值,给每个单词分配一个变量
所有剩余单词都被分配给最后一个变量
read -p “Enter a filename: “ FILE

let

 bash中的算术运算:help let
+, -, *, /, %取模(取余), **(乘方)
实现算术运算:
(1) let var=算术表达式
(2) var=$[算术表达式]
(3) var=$((算术表达式))
(4) var=$(expr arg1 arg2 arg3 ...)
(5) declare –i var = 数值
(6) echo ‘算术表达式’ | bc
乘法符号有些场景中需要转义,如*  bash有内建的随机数生成器:$RANDOM(0-32767)
echo $[$RANDOM%50] :0-49之间随机数

 增强型赋值:
+=, -=, *=, /=, %=let varOPERvalue
例如:let count+=3
 自加3后自赋值
 自增,自减:
let var+=1
let var++
let var-=1
let var--

1、编写脚本/root/bin/systeminfo.sh,显示当前主机系统信息,包括主机名,IPv4地址,操作系统版本,内核版本,CPU型号,内存大小,硬盘大小

#!/bin/bash
BEGINCOLOR="\e[1;35m"
ENDCOLOR="\e[0m"
 
echo -e "My hostname is ${BEGINCOLOR}`hostname`$ENDCOLOR"
echo -e "IP address is ${BEGINCOLOR}`ifconfig ens33 |grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}'|head -n1`$ENDCOLOR"
echo -e "OS version is ${BEGINCOLOR}`cat /etc/redhat-release`$ENDCOLOR"
echo -e "Kernel version is ${BEGINCOLOR}`uname -r`$ENDCOLOR"
echo -e "CPU type is ${BEGINCOLOR}`lscpu|grep "Model name" |cut -d: -f2 |tr -s " "`$ENDCOLOR"
echo -e "Memtotol is ${BEGINCOLOR}`cat /proc/meminfo |head -n1 |grep -Eo '[0-9]+.*'`$ENDCOLOR"
echo -e "Disk space is ${BEGINCOLOR}`lsblk |grep 'sda\>'|grep -Eo '[0-9]+[[:upper:]]'`$ENDCOLOR"

Shell 练习题(二)_第1张图片

grep
‘[:upper:]’
大写字母类。包括:‘A B C D E F G H I J K L M N O P Q R S T U V W X Y Z’。
-A,–after-context=NUM 输出当前行以及向后数NUM数的所有行
-B,–before-context=NUM 输出当前行以及向前数NUM数的所有行
-C,–context=NUM 输出当前行以及向前向后各数NUM数的所有行
-c,–count 统计每个文件中包含指定字符串的行数
-e,–regexp=PATTERN 用PATTERN来进行匹配操作
-E,–extended-regexp PATTERN是一个可扩展的正则表达式(缩写ERE)
-f<范本文件>,–file=FILE 指定范本文件,其内容有一个或多个范本样式,让grep查找符合范本条件的文件内容,格式为每一行的范本样式
-F,–fixed-strings PATTERN是一个由断行符分隔的定长字符串(取消默认的基本正则表达式)
-h,–no-filename 输出时不显示文件名前缀
-i,–ignore-case 忽略大小写
-l,–files-with-match 只显示包含指定字符串的文件名
-n,–line-number 输出的同时显示行号
-o,–only-matching 只显示匹配到的字符串
-q,–quiet,–silent 静默模式,不输出任何信息
-s,–nomessages 不显示不存在或无法匹配的错误信息
-v,–invert-march 显示不匹配的行
-V,-version 显示版本信息
-w,–word-regexp 匹配整个单词
–color=auto 对匹配到的文本着色显示

2、编写脚本/root/bin/backup.sh,可实现每日将/etc/目录备份到/root/etcyyyy-mm-dd中

#!/bin/bash
cp -a /etc/ /root/etc`date +%F` && echo "备份完成"

3、编写脚本/root/bin/disk.sh,显示当前硬盘分区中空间利用率最大的值

#!/bin/bash
##编写脚本/root/bin/disk.sh,显示当前硬盘分区中空间利 用率最大的值
maxdisk=`df | grep "/dev/sd" | tr -s " " ":" | cut -d : -f5 | sort -nr | head -n1`
maxuse=`df | grep "/dev/sd" | tr -s " " ":" | cut -d : -f1 | sort -nr | head -n1`
echo "磁盘"$maxuse"使用量为:"$maxdisk

4、编写脚本/root/bin/links.sh,显示正连接本主机的每个远程主机的IPv4地址和连接数教并按连接数从大到小排序

#!/bin/bash
##编写脚本/root/bin/links.sh,显示正连接本主机的每个远 程主机的IPv4地址和连接数,并按连接数从大到小排序
echo -e "远程主机连接统计为:\n\t连接数\t远程主机IP"
netstat -nt | tr -s " " | cut -d " " -f5 | cut -d : -f1 | sort -n | uniq -c |tr -s " " "\t"| egrep '([0-9]+.){3}[0-9]+'

————————————————————————————————————————

1、编写脚本/root/bin/sumid.sh,计算/etc/passwd文件中的第10个用户和第20用户的ID之和

#!/bin/bash
user10=`cat /etc/passwd | cut -d: -f3 | sed -n "10p"`
user20=`cat /etc/passwd | cut -d: -f3 | sed -n "20p"`
let Num=$user10+$user20  #如果不用let,就单单只是两个数字的拼接为字符串而已
echo $Num

2、编写脚本/root/bin/sumspace.sh,传递两个文件路径作为参数给脚本,计算这两个文件中所有空白行之和

#!/bin/bash
File1=$(grep "^$" $1 | wc -l)  # ^代表行首 $代表行尾 ^$意思就是行首之后就是行尾,中间什么也没有 所以代表空行
File2=$(grep "^$" $2 | wc -l)
let Sumlink=$File1+$File2
echo "the sum of $1 and $2 spacelines is $Sumlink"

3、编写脚本/root/bin/sumfile.sh,统计/etc,/var,/usr目录中共有多少个一级子目录和文件

#!/bin/bash
##写一个脚本/root/bin/sumfile.sh,统计/etc, /var, /usr目录中共有多少个一级子目录和文件
num1=$(ls -l /etc | wc -l)
num2=$(ls -l /var | wc -l)
num3=$(ls -l /usr | wc -l)
let Num=$num1+$num2+$num3
echo $Num

————————————————————————————————————————

1、编写脚本/root/bin/argsnum.sh,接受一个文件路径作为参数;如果参数个数小于1,则提示用户“至少应该给一个参数”,并立即退出;如果参数个数不小于1,则显示第一个参数所指向的文件中的空白行数

#!/bin/bash
[[ $1 == "" ]] && echo "please enter a parameter" || echo $(grep "^$" $1 | wc -l)

在这里插入图片描述
2、编写脚本/root/bin/hostping.sh,接受一个主机的IPv4地址做为参数,测试是否可连通。如果能ping通,则提示用户“该IP地址可访问”;如果不可ping通,则提示用户“该IP地址不可访问”

#!/bin/bash
# =~:正则匹配,用来判断其左侧的参数是否符合右边的要求
ipaddr='(\<([0-9]|[1-9][0-9]|1[0-9]{2}|2([0-4][0-9]|5[0-5]))\>\.){3}\<([0-9]|[1-9][0-9]|1[0-5][1-9]|2([0-4][0-9]|5[0-4]))\>'
    read -p "please input a IPV4 addr: " ipv4
    if [[ $ipv4 =~ $ipaddr ]];then 
        echo "a legal IP."
        ping $ipv4 -c 4
        echo "这个IP可以正常访问"
    else
        echo "unlegal IP"
        echo "请输入正确的地址"
        exit
    fi

IPV4地址由4个组数字组成,每组数字之间以.分隔,每组数字的取值范围是0-255。
IPV4必须满足以下四条规则:
1、任何一个1位或2位数字,即0-99;
2、任何一个以1开头的3位数字,即100-199;
3、任何一个以2开头、第2位数字是0-4之间的3位数字,即200-249;
4、任何一个以25开头,第3位数字在0-5之间的3位数字,即250-255。

注意正则表达式最后一位IP地址,如果是255的话就是广播地址,这里我特意省略了
如果也要包括的话就在最后改为 2([0-4][0-9]|5[0-5])

Shell 练习题(二)_第2张图片

3、编写脚本/root/bin/checkdisk.sh,检查磁盘分区空间和inode使用率,如果超过80%,就发广播警告空间将满

#!/bin/bash
a="`df |grep ^/dev/sd |tr -s " " ":"|cut -d: -f5 |cut -d% -f1 |sort -nr`"
if [ $a -gt 80 ]
then
    echo "WARING!!!"
else
    echo "Nothing.."
fi

Shell 练习题(二)_第3张图片————————————————————————————————————————

存在性测试

存在性测试
-a FILE:同-e
-e FILE: 文件存在性测试,存在为真,否则为假

存在性及类别测试
-b FILE:是否存在且为块设备文件
-c FILE:是否存在且为字符设备文件
-d FILE:是否存在且为目录文件
-f FILE:是否存在且为普通文件
-h FILE 或 -L FILE:存在且为符号链接文件
-p FILE:是否存在且为命名管道文件
-S FILE:是否存在且为套接字文件

文件权限测试:
-r FILE:是否存在且可读
-w FILE: 是否存在且可写
-x FILE: 是否存在且可执行

文件特殊权限测试:
-u FILE:是否存在且拥有suid权限
-g FILE:是否存在且拥有sgid权限
-k FILE:是否存在且拥有sticky权限

文件大小测试:
-s FILE: 是否存在且非空

文件是否打开:
-t fd: fd 文件描述符是否在某终端已经打开
-N FILE:文件自从上一次被读取之后是否被修改过
-O FILE:当前有效用户是否为文件属主
-G FILE:当前有效用户是否为文件属组

双目测试:
FILE1 -ef FILE2: FILE1是否是FILE2的硬链接
FILE1 -nt FILE2: FILE1是否新于FILE2(mtime)
FILE1 -ot FILE2: FILE1是否旧于FILE2
 
=~:正则匹配,用来判断其左侧的参数是否符合右边的要求

1、编写脚本/bin/per.sh,判断当前用户对指定的参数文件,是否不可读并且不可写

#!/bin/bash
##chmod -rw /tmp/file1,编写脚本/root/bin/per.sh,判断当前用户对/tmp/fiile1>文件 是否不可读且不可写 ?
flie1=/home/soft/zuoye/file
[ -r $file1 ]
arg1=$(echo $?)
echo $arg1
[[ $arg1 -eq 0 ]] && echo "该用户对此文件有读的权限" || echo "该用户对此文件没有
读的权限"
[ -w $file1 ]
arg2=$(echo $?)
echo $arg2
[[ $arg2 -eq 0 ]] && echo "该用户对此文件有写的权限" || echo "该用户对此文件没有
写的权限"

2、编写脚本/root/bin/excute.sh,判断参数文件是否为sh后缀的普通文件,如果是,添加所有人可执行权限,否则提示用户非脚本文件

#!/bin/bash
# =~:正则匹配,用来判断其左侧的参数是否符合右边的要求
read -p "Please input a filename: " file
if [[ $file =~ .*sh$ ]] ; then
        if [ -f $file ] ; then
                chmod a+x $file
                echo "success"
        fi
else
        echo '非脚本文件' 
fi

3、编写脚本/root/bin/nologin.sh和login.sh,实现禁止和允许普通用户登录系统

tr命令详解

#!/bin/bash
# tr将空白转为@,
read -p "请输入禁止的用户:" user
uid=$( id $user |tr " " @ |cut -d@ -f1 |grep -o "[0-9]\{3,\}" )
#  $( id $user  | cut -d" " -f1 |grep -o "[0-9]\{3,\}"  )

[ $uid -ge 500 ] && usermod -s /bin/nologin $user || echo '该用户为系统用户,无法禁止!'
echo '该用户已禁止登陆'
#!/bin/bash
read -p "请输入允许登录的用户:" user
uid=$( id $user |tr " " @ |cut -d@ -f1 |grep -o "[0-9]\{3,\}" )
[ $uid -ge 500 ] && usermod -s /bin/bash $user || echo '该用户为系统用户'
echo '该用户已允许登陆'

cut [OPTION]… [FILE]…
cut 命令并不直接操作于源文件,而是操作输出缓冲。
-d:指定字段分隔符,默认是空格 -d:
-f: filed 指定要显示的字段列表 eg:-f1 显示第一个字段 -f1,3 显示一三字段 -f1-3显示一到三字段,
字段从左到右 依次增大,从1开始。

————————————————————————————————————————

1、让所有用户的PATH环境变量的值多出一个路径,例如:
/usr/local/apache/bin

echo "PATH=$PATH:/usr/local/apache/bin">>/etc/profile.d/path.sh
vim /etc/profile.d/env.sh
export PATH=/usr/local/apache/bin:$PATH
source /etc/profile.d/env.sh

2、用户root登录时,将命令指示符变成红色,并自动启用如下别名:
rm=‘rm –i’
cdnet=‘cd /etc/sysconfig/network-scripts/’
editnet=‘vim /etc/sysconfig/network-scripts/ifcfg-eth0’
editnet=‘vim /etc/sysconfig/network-scripts/ifcfgeno16777736 或 ifcfg-ens33 ’ (如果系统是CentOS7)

命令符红色 和 定义别名:

在 ~/.bashrc中将放入以下命令:
PS1='\[\e[1;31m\][\u@\h \w]\$\[\e[0m\]'
alias rm='rm –i'
alias cdnet='cd /etc/sysconfig/network-scripts/'
alias editnet='vim /etc/sysconfig/network-scripts/ifcfg-eth0'
alias editnet='vim /etc/sysconfig/network-scriptsifcfg-ens33'

这里注意要su切换
Shell 练习题(二)_第4张图片
Shell 练习题(二)_第5张图片
3、任意用户登录系统时,显示红色字体的警示提醒信息
“Hi,dangerous!”

在/etc/profile.d/env.sh 中添加
echo -e "\e[1;31mHi,dangerous ! \e[0m"

4、编写生成脚本基本格式的脚本,包括作者,联系方式,版本,时间,描述等

vim ~/.vimrc

set nu "show line
set ts=4 "TAB 4 chars
syntax on "grammar light
set cursorline
"set mouse=a
set ai
autocmd BufNewFile *.sh exec ":call SetTitle()"
func SetTitle()
     if expand("%:e")=='sh'
             call setline(1,"#!/bin/bash")
             call setline(2,"#")
             call setline(3,"#**************")
             call setline(4,"#author:果子哥")
             call setline(5,"#QQ:xxxxxxxx")
             call setline(6,"#email:[email protected]")
             call setline(7,"#version:x.0")
             call setline(8,"#date: ".strftime("%Y-%m-%d"))
             call setline(9,"#description: script")
             call setline(10,"#*************************************")
     endif
endfunc
autocmd BufNewFile * normal G   #自动将光标定位到末尾

5、编写用户的环境初始化脚本reset.sh,包括别名,登录提示符,vim的设置,环境变量等

vim reset.sh
...
cat >> ~/.bash_profile << EOF
PS1='\[\e[1;8;$[RANDOM%6+41]m\][\u@\h \w]\$\[\e[0m\]'
export REGEX_IP='(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])[.]){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])'
EOF

#config bashrc
cat >> ~/.bashrc << EOF
alias cdnet='cd /etc/sysconfig/network-scripts/'
EOF

#config vimrc
cat >> ~/.vimrc << EOF
set nu "show line
set ts=4 "TAB 4 chars
syntax on "grammar light
set cursorline
"set mouse=a
set ai
autocmd BufNewFile *.sh exec ":call SetTitle()"
func SetTitle()
     if expand("%:e")=='sh'
             call setline(1,"#!/bin/bash")
             call setline(2,"#")
             call setline(3,"     #*************************************")
             call setline(4,"     #author:果子哥")
             call setline(5,"     #QQ:123456")
             call setline(6,"     #email:[email protected]")
             call setline(7,"     #version:x.0")
             call setline(8,"     #date: ".strftime("%Y-%m-%d"))
             call setline(9,"     #description: script")
             call setline(10,"     #*************************************")
     endif
endfunc
autocmd BufNewFile * normal G   #自动将光标定位到末尾
EOF

Shell 练习题(二)_第6张图片

————————————————————————————————————————

1、编写脚本/root/bin/createuser.sh,实现如下功能:使用一个用户名做为参数,如果指定参数的用户存在,就显示其存在,否则添加之;显示添加的用户的id号等信息

#!/bin/bash
 if [ $# -eq 0 ];then
     echo "one argument (username) is required!" 
     exit
 elif [ $# -gt 1 ];then
     echo "required 1 argument, but $# arguments were supplied!"
     exit
 fi  

useradd $1 &> /dev/nul
USER_EXIT=$?
[ $USER_EXIT  -eq 9 ] && echo "createuser.sh: user $1 already exists" && exit 9
[ ! $USER_EXIT -eq 0 ] && echo "createuser.sh: ERROR"

id $1

在这里插入图片描述

2、编写脚本/root/bin/yesorno.sh,提示用户输入yes或no,并判断用户输入的是yes还是no,或是其它信息

#!/bin/bash
read -p "Please input [Yes/No]:" YESORNO
case $YESORNO in
[Yy][Ee][Ss]|[Yy])
echo "you choose yesyes"
;;
[Nn][Oo]|[Nn])
echo "you choose no"
;;
*)
echo "you choose other"
esac

3、编写脚本/root/bin/filetype.sh,判断用户输入文件路径,显示其文件类型(普通,目录,链接,其它文件类型)

#!/bin/bash
[ $# -lt 1 ] && echo "Please input unless one argument!" && exit
for count in `seq 1 $#`
do
CHAR=$(eval ls -dl \$$count | cut -c 1)
CO="\e[1;32m"
LOR="\e[0m"
case $CHAR in
-)
        echo -e "The file type is \e[1;32mnormal file\e[0m"
        ;;
l)
        echo -e "The file type is $CO link file $LOR"
        ;;
d)
        echo -e "The file type is $CO directory $LOR"
        ;;
*)
        echo "sorry,I still don't know the file type "
esac
done

4、编写脚本/root/bin/checkint.sh,判断用户输入的参数是否为正整数

#!/bin/bash
[ $# -lt 1 ] && echo "Please intput unless one argument" && exit
[ $# -gt 1 ] && echo "I just can understand one argument" && exit
[[ $1 =~ ^[0-9]*$ ]] && echo "your argument is a positive integer" || echo "your argument isn't a INT"

你可能感兴趣的:(#,Shell,shell)