定向输出,算数运算,正则表达式
shell的特性之十:输入输出定向和管道
I/O,设备,寄存器
I/O port
Linux:一切皆文件
文件描述符:file descriptor FD 追踪被打文件的各种属性
INPUT:标准输入,(stdin) FD = 0 键盘
OUPUT:标准输出,(stdout) FD = 1 显示器
标准错误,(stderr) FD = 2
IO重定向:(输出到显示器上的输出到其位置,)
1.输入重定向
<:输入重定向
<<:此处创建文件
常用于在脚本中创建文件或生成菜单
---------例1---------------------------------------
#!/bin/bash
#
cat << EOF
a: show user info
b: show group info
c: show cpu onfo
EOF
-----
[kayshi@localhost ~]$ bash menu.sh
a:show user info
b:show disk info
c:show cpu info
-----------例2------------
#!/bin/bash
#
cat > 4.txt << EOF
a: show user info
b: show group info
c: show cpu onfo
EOF
---------
[kayshi@localhost ~]$ bash menu.sh
[kayshi@localhost ~]$
[kayshi@localhost ~]$ cat 4.txt
a: show user info
b: show group info
c: show cpu onfo
--------------------------------------------
2.输出重定向:
>:覆盖输出
>>:追加输出
set -C:禁止使用覆盖重定向之已存在的文件;
set +C:关闭上述特性;
>|:在-C特性下,强制使用覆盖重定向
/dev/null:(bit buket,位桶)输入的数据都被丢弃
ls /etc/ > /dev/null :只要结果,不要过程
3.错误重定向:
错误重定向 2> , 2>>
2>:覆盖
2>>:追加
同时使用:
command > path/to/outfile 2> /path/to/errfile 成功或失败都输出到不同文件
command &> /path/to/somefile :成功或失败都输出到一个文件
command > /path/to/somefile 2>&1 : 成功或失败都输出到一个文件
-------------------例如-----------------------------
[root@localhost tmp]# lsl /etc/ > 1.txt 2>2.txt
-----------------------------------------
[root@localhost tmp]# lsl /etc/ &> 1.txt
[root@localhost tmp]# $?
-bash: 127: command not found
[root@localhost tmp]# cat 1.txt
-bash: lsl: command not found
-------------------------------------------
[root@localhost tmp]# lsl /dev/ > 1.txt 2>&1
[root@localhost tmp]# $?
-bash: 127: command not found
[root@localhost tmp]# cat 1.txt
-bash: lsl: command not found
4.管道
linux:
使用单一的小程序
组合小程序来完成复杂的任务
COMMAND1 | COMMAND2 | COMMAND3 | ...
COMMAND1的结果进入COMMAND2中,那如果想查看COMMAND1怎么办?
tee 相当于T路口,在COMMAND1上开个管道到我tee的位置,同时还保留着到COMMAND2的管道
COMMAND1| tee /path.file |COMMAND2
例如:
[kayshi@localhost ~]$ cat /etc/rc.d/rc.sysinit | tee /home/kayshi/5.txt |wc -l
680
[kayshi@localhost ~]$ cat /home/kayshi/5.txt
#!/bin/bash
#
# /etc/rc.d/rc.sysinit - run once at boot time
#
# Taken in part from Miquel van Smoorenburg's bcheckrc.
#
HOSTNAME=$(/bin/hostname)
bash中的数据运算:
变量默认字符型,不会直接算数运算
declare(宣告)
-i:整型
-x:环境变量,类似于export
let
1.let varName=算数表达式
如果计算数据中存在小数,将会被圆整;(省略)
2.varname=$[算数表达式]
3.varname=$((算数表达式))
4.varnamw=`expr $num1 + $nume2`
--------bash 参数---
bash -x script.sh 可以显示出单步的过程
----------
[kayshi@localhost ~]$ let sum=4+3
[kayshi@localhost ~]$ echo $sum
7
[kayshi@localhost ~]$ var=$[4+3]
[kayshi@localhost ~]$ echo $var
7
[kayshi@localhost ~]$ var=$((4+4))
[kayshi@localhost ~]$ echo $var
8
[kayshi@localhost ~]$ expr 4 + 5
9
------------
操作符:+,-、*,/,%
+=,-=,*=,/=,%=
++ --
练习
1.计算100以内的整数之和
2.计算100的偶数之和和技术之和
3.计算所有用户ID之和
4.计算/etc/rc.d/rc.sysinit,/etc/init.d/functions /etc/issue字符数之和
5.新建用户tepuser1-tempuser10,并就算uid之和
1.
#!/bin/bash
sum=1
for num in {1..100};do
let sum=$sum+$num
done
echo $sum
2.
declare -i enev=0
declare -i odd=0
for num in `seq 1 2 100`;do
let enev=$enev+$num
done
echo "sum of enev:$enev"
for num in `seq 2 2 100`;do
let odd=$odd+$num
done
echo "sum of odd:$odd"
3.
#!/bin/bash
declare -i uid_sum=0
for id_num in `cat /etc/passwd | cut -d: -f3`;do
let uid_sum=$uid_sum+$id_num
done
echo "UID sum is:$uid_sum"
4.
#!/bin/bash
declare -i charSum=0
for charNum in `wc -c /etc/rc.d/rc.sysinit | cut -d' ' -f1` `wc -c /etc/init.d/functions | cut -d' ' -f1` `wc -c /etc/issue | cut -d' ' -f1`;do
let charSum=$charSum+$charNum
done
echo "sum is $charSum"
5.
#!/bin/bash/
declare -i uidSum=0
for users in `seq 1 10`;do
useradd tmpuser$users
#uidNum=`tail -1 /etc/passwd | cut -d: -f3`
uidNum id -u tmpuser$users
let uidSum=$uidSum+$uidNum
done
echo "user id sum is:$uidSum"
=====================================================
知识点:位置参数
位置参数:
$0:脚本自身
$n:脚本第n个参数(n=0,1,2,3..)
特殊参数:
$#:参数的个数
$*,$@:引用所有参数
------------例子---
#!/bin/bash
echo $0
echo $1
echo $2
let sum=$1+$2
echo "sum=$[$1+$2]"
echo $#
echo $*
echo $@
[kayshi@localhost ~]$ bash test8.sh 4 6 56 6
test8.sh
4
6
sum=10
4
4 6 56 6
4 6 56 6
知识点:交互式脚本
read
给变量
${varName:-value}
如果varName不空,返回varName的值不变,否则返回value
varName=${varName:-value}
如果varName不空,值不变,否则值为value
——–练习—
#!/bin/bash
echo -n -e "\033[31minput a number\033[0m"
read var1
echo $var1
read -p "input a number" var2
echo $var2
read -t 5 -p "input a number" var3
var3=${var3:-222}
echo $var3
read -p "input a file path" fileName
file $fileName
-----------
输入
#!/bin/bash
read -p "Enter a path:" Path
Path=${Path:-/}
Num=`ls $Path | wc -l`
for i in `seq 1 $Num`;do
filename=`ls $Path | head -n $i | tail -1`
file $filename
done
通过键盘输入一个路径,默认为/ ,判断路径下文件的内容类型
#!/bin/bash
read -t 5 -p "Enter a path:" Path
Path=${Path:-"/"}
Num=`ls $Path | wc -l`
for i in `seq 1 $Num`;do
filename=`ls $Path | head -n $i | tail -1`
file $filename
done
grep
grep:(global search regular expression(RE),and print out the line)
文本搜索工具
格式:grep [option] 'PATTERN' file,...
正则表达式:是一类字符所书写的模式(pattern)
元字符:不表示字符本身的意义,而是用于额外的功能性的描述
基本正则表达式和扩展正则表达式
基本正则表达式:grep -E
---------
字符匹配:
. :任意单个字符
[]:范围字符
[0-9],[[:digit]]
[a-z],[[:lower:]]
[A-Z],[[:upper:]]
[[:alpha:]] 字母
[[:alnum:]] 字母加数字
[[:space:]] 空白
[[:punct:]] 符号
[^]:范围以外
-----------
次数匹配:匹配指定匹配其前面的字符的次数
* :任意次
例子:x*y == xxy, xy, y
.*: 匹配任意长度的任意字符
\?: 0次或一次
x\?y== xy, y
贪婪模式:尽可能的长的去匹配字符
\{m\}:匹配m次
\{m,n\}:m到n次
\{m,\}:至少m次
\{0,n\}:最多n次
-----------
位置锚定:用来指定字符出现的位置
^:用于锚定行首
^Char
$:锚定行尾
char$
^$:空白行
^hello$:代表只有hello的行
----
\<char:锚定词首 或者 \bchar
char\>:锚定词尾 或者 char\b
\<h..o\>:表示已h开头,以o结尾,中间的两个的任意字符的的单词
--------
ab*xy: a后面跟了任意个b再跟xy(*只能匹配紧挨着的前面的一个字符)
分组:
\(\)
\(ab\)*xy 任意个ab再跟xy
引用:
\1:后向引用,引用前面第一和左括号以及与之对应的右括号中的模式所匹配到的内容
\(a.b\)*xy\1:a6bxya6b \1
---例----
[kayshi@localhost ~]$ cat test11.txt
a6bxya7b
a6bxya6b
[kayshi@localhost ~]$ cgrep '\(a.b\)xy\1' test11.txt
a6bxya6b
grep 常用选项:
-v : 反向匹配
-o : 仅匹配被匹配到的字串,而非整行
-i : 不区分大小
-E :支持扩展正则表达式
-A :显示查找到的行并加上下一行
-B :显示查找到的行并加上上一行
-C :显示查找到的行并加上上下两行
——练习——
1、显示/proc/meminfo文件中的以大小写s的开头的行
2、取出默认shell为非bash的用户
3、取出默认shell为bash的且其ID号最大的用户
4、显示/etc/rc.d/rc.sysinit文件中,以#开头,后面跟至少一个空白字符,而后又有至少一个非空白字符的行
5、显示/boot/grub/grub.conf中以至少一个空白字符的行
6、查出/etc/passwd中一位数或两位数
7、找出ifconfig命令结果中的1到255之间的整数
8、查看当前系统上root用户的所有信息
9、添加用户bash和testbash,而后找出当前系统上于其他用户名和默认shell相同的用户
10、找出netstat -tan命令执行的结果中以“LISTEN”或“ESTABLISHEN”结尾的行
11、取出当前系统上所有用户的shell,要求:每种shell中显示一次,且升序排序显示
挑战题
—–答案—–
1.grep '^[Ss]' /proc/meminfo
或grep -i "^s" /proc/meminfo
2.grep -v 'bash\>' /etc/passwd
他人:grep -v "bash$" /etc/passwd |cut -d: -f1
3.grep 'bash\>' /etc/passwd | cut -d: -f1 | sort -n | tail -1
他人:grep "bash$" /etc/passwd |cut -d: -f1|sort -n -t: -k3|tail -1
4.grep '^#[[:space:]]\{1\}[^[:space:]]\{1,\}' /etc/rc.d/rc.sysinit
他人:grep "^#[[:space:]]\{1,\}[^[:space:]]\{1,\}" /etc/rc.d/rc.sysinit
5.grep '^[[:space:]]\{1,\}[^[:space:]]\{1,\}' /boot/grub/grub.conf
他人:grep "^[[:space:]]\{1,\}" /boot/grub/grub.conf
6.grep --color=auto '\<[[:digit:]]\{1,2\}\>' /etc/passwd
他人:grep --color=auto "\<[0-9]\{1,2\}\>" /etc/passwd
7.ifconfig | grep --color=auto '\<[0-9]\{1,3\}\>'
他人: ifconfig |grep -E --color=auto "\<([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\>"
8.cat /etc/passwd | grep ^root>\
grep “\<root\>”/etc/passwd
9.grep --color=auto '^\([[:alnum:]]\{1,\}\).*\1$' /etc/passwd
grep “^\([[:alnum:]]\{1,\}\)\>.*\1$” /etc/passwd
10.
metstat -tan |grep -E “(LISETN|ESTABLISHED)[[:space:]]*"
11.cut -d: -f7 /etc/passwd | sort -u
cut -d: -f7 /etc/passwd|sort -u
grep egrep fgrep
egrep:使用扩展正则表达式来构建模式,相当于grep -E
元字符:
字符匹配:
. : 任意单个字符
[]: 指定范围内的任意单个字符
[^]: 指定范围外的任意单个字符
次数匹配:
*:匹配其前面的字符任意次
?: 匹配其前面的字符0或1次
+:匹配其前面的字符至少1次
{m}:匹配其前面的字符m次
{m,n}:m到n次
{m,}:大于等于m次
{,n}:小于等于n次
分组:
(): 分组
| : 或者 ac|bc = ac 或者 bc
bash编程之条件判断:判定后续操作的前提条件是否满足,
条件判断的常用判断类型:
整数测试:
字符测试:
文件测试:
$?:
0:正确
1-255:错误
布尔值:
真 假
逻辑运算:
与运算:
真 && 真 = 真(0)
真 && 假 = 假
假 && 真 = 假
假 && 假 = 假
或运算:
真 || 真 = 真(0)
真 || 假 = 真
假 || 真 = 真
假 || 假 = 假
非运算:
!真 = 假
!假 = 真
bash中如何做测试
test 表达式
[ 测试表达式 ]
[[ 测试表达式 ]]
bash中条件判断使用if:
单分支:
if 条件; then
分支1;
fi
双分支:
if 条件; then
分支1;
else
分支2;
fi
多分支:
if 条件; then
分支1;
elif 条件2; then
分支2;
elif 条件3; then
分支3;
…
else
分支n;
fi
只要命令用作条件,就表示引用的是其状态结果(即执行成功与否),而非命令的输出结果,因此,不能使用命令替换符.
bash编程之:整数测试
二元测试:
num1 操作符 num2
-eq: 等于
-ne:不等于
-le:小于等于
-ge:大于等于
-lt:小于
-gt: 大于
bash知识点之脚本自动退出
exit n n为不为0,1,127,255的数字
1.练习:写一脚本,实现如下功能:
1、让用户通过键盘输入一个用户名
2、如果用户存在,就显示其用户名和UID;
3、否则,就显示用户不存在;
2.练习:写一脚本,实现如下功能:
1、让用户通过键盘输入一个用户名,如果用户不存在就退出;
2、如果用户的UID大于等于500,就说明它是普通用户;
3、否则,就说明这是管理员或系统用户;
3.练习:写一脚本,实现如下功能:
1、让用户通过键盘输入一个用户名,如果用户不存在就退出;
2、如果其UID等于其GID,就说它是个”good guy”
3、否则,就说它是个“bad guy”;
4.练习:写一个脚本,实现如下功能:
1、添加10个用户stu1-stu10;但要先判断用户是否存在;
2、如果存在,就用红色显示其已经存大在
3、否则,就添加此用户;并绿色显示;
4、最后显示一共添加了几个用户;
1.
#!/bin/bash
read -t -p "Enter a username: " userName
#userName=${userName:-root}
if id $userName &> /dev/null; then
uid=`id -u $userName`
echo "user:$userName uid:$uid"
else
echo "$userName not exist!"
fi
2.
#!/bin/bash
read -p "Enter a username: " userName
if grep "^$userName\>" /etc/passwd >> /dev/null; then
#uid=`id -u $userName`
uid=`grep "^$userName\>" /etc/passwd | cut -d: -f3`
if [ $uid -gt 500 ]; then
echo "user in normal users"
else
echo "user in system users"
fi
else
echo "$userName not exist!"
exit 4
fi
3.
#!/bin/bash
read -p "Enter a username: " userName
if grep "^$userName\>" /etc/passwd >> /dev/null;then
uid=`grep "^$userName\>" /etc/passwd | cut -d: -f 3`
gid=`grep "^$userName\>" /etc/passwd | cut -d: -f 4`
if [ $uid -eq $gid ]; then
echo "good guy"
else
echo "bad guy"
fi
else
echo "user in not here"
fi
4.
#!/bin/bash
declare -i cnt=0
for unum in `seq 1 10`;do
if grep "^std$unum\>" /etc/passwd >> /dev/null;then
echo -e "\e[31mstd$unum\e[0m is already exist"
#userdel std$unum
else
useradd std$unum && echo -e "\e[32mstd$unum\e[0m add successful"
let cnt++
fi
done
echo "add the number of user is:$cnt"
练习1-200能被3数字之和
#!/bin/bash
declare -i sum=0
for num in `seq 1 200`;do
if [ $[$num%3] -eq 0 ];then
let sum=$sum+$num
fi
done
echo "sum is: $sum"