输入输出重定向和管道
INPUT: 标准输入stdin0
OUPUT: 标准输出stdout1
标准错误stderr2
I/O重定向
输入重定向:<, <<
<: 输入重定向
<< EOF: 此处创建文件, Here Document
常用于在脚本中创建文件或生成菜单;
显示如下菜单
c:show cpu info
d:show disk inf
m:show men info
脚本实现
#!/bin/bash
cat << EOF
c:show cpu info
d:show disk info
m:show men info
EOF
输出重定向:>, >>
>: 覆盖输出
>>: 追加输出
set -C:禁止使用覆盖重定向至已经存在的文件;
set +C: 关闭上述特性;
>|:在-C特性下,强制使用覆盖重定向;
/dev/null: bit bucket,位桶
错误重定向:2>, 2>>
2>: 覆盖
2>>: 追加
同时重定标准输出和错误输出:
COMMAND > /path/to/outfile 2> /path/to/errfile
COMMAND &> /path/to/somefile
COMMAND > /path/to/somefile 2>&1
管道:
COMMAND1 | COMMAND2 | COMMAND3 | ...
bash中的算术运算
declare
-i: 整型变量
-x: 环境变量, 类似于export
let varName=算术表达式
varName=$[算术表达式]
varName=$((算术表达式))
varName=`expr $num1 + $num2`
如果计算结果中存在小数,将会被圆整:
操作符:+, -, *, /, %
+=, -=, *=, /=, %=
练习:计算100以内所有正整数之和;
#!/bin/bash
#
declare -i sum=0
for i in {1..100}; do
let sum=$sum+$i
done
echo "The sum is: $sum."
知识点:bash的单步执行:
bash -x /path/to/script
练习:分别计算100以内所有偶数之和和奇数之和;
#!/bin/bash
declare -i oddSum=0,evenSum=0
for i in `seq 1 2 100`; do
oddSum=$[$oddSum+$i]
done
for j in `seq 2 2 100`; do
evenSum=$[$evenSum+$j]
done
echo "The Even Sum is: $evenSum, the odd sum is: $oddSum"
练习:计算当前系统所有用户的ID之和;
#!/bin/bash
declare -i uidSum=0
for i in `cut -d: -f3 /etc/passwd`; do
uidSum=$[$uidSum+$i]
done
echo "The UIDSum is: $uidSum."
练习:计算/etc/rc.d/rc.sysinit、/etc/init.d/functions和/etc/issue三个文件的字符数之和;
#!/bin/bash
#
declare -i bytesCount=0
for file in /etc/rc.d/rc.sysinit /etc/init.d/functions /etc/issue; do
let bytesCount=$bytesCount+`wc -c $file | cut -d' ' -f1`
done
echo $bytesCount
练习:新建用户tmpuser1-tmpuser10,并计算他们的id之和;
#!/bin/bash
#
declare -i uidSum=0
for i in {1..10}; do
useradd tmpuser$i
let uidSum=$uidSum+`id -u tmpuser$i`
done
知识点:位置参数
位置参数:
/tmp/test.sh 3 89
$0: 脚本自身
$1: 脚本的第一个参数
$2
...
特殊变量:
$#: 位置参数的个数;
$*,$@: 引用所有的位置参数;
知识点:交互式脚本
read
-t指定输入超时时间
-p可以输入提示语
知识点:给变量以默认值
varName=${varName:-value}
如果varName不空,则返回varName的值;否则,则返回value;
如果varName不空,则其值不变;否则,varName会使用value作为其值;
练习:通过键盘给定一个目录路径,默认为/,来判断目录下文件内容的类型;
#!/bin/bash
read -t 5 -p "Please input a dirPath:" dirPath
dirPath=${dirPath:-"/"}
echo "The dirPath what you input is: $dirPath"
for filename in "$dirPath/*"
do
file $filename
done
文本处理工具之grep、egrep和fgrep:
grep: (global search regular expression(RE) and print out the line
文本搜索工具,根据用户指定的文本模式对目标文件进行逐行搜索,显示能够被模式所匹配到的行
格式:grep [options] 'PATTERN' file,...
grep 常用选项:
-v反向,显示不能被模式所匹配到的行;
-o仅显示被模式匹配到的字串,而非整行;
-i不区分字符大小写, ignore-case
-E支持扩展的正则表达式
-A #显示匹配行后面的#行
-B #显示匹配行前面的#行
-C #显示匹配行前后的#行
--color=auto 颜色显示匹配到的字符
正则表达式:是一类字符所书写出的模式(pattern)
元字符:不表示字符本身的意义,用于额外功能性的描述
基本正则表式的元字符:grep -E
字符匹配:
.匹配任意单个字符
[]匹配指定范围内的任意单个字符
[^]匹配指定范围外的任意单个字符
[0-9], [[:digit:]] 匹配数字0-9
[a-z], [[:lower:]] 匹配小写字母a-z
[A-Z], [[:upper:]] 匹配大写字母A-Z
[[:alpha:]]匹配所有字母a-zA-Z
[[:alnum:]]匹配所有字母数字0-9a-zA-Z
[[:space:]]匹配所有空白字符
[[:punct:]]匹配所有标点符号
次数匹配:用来指定匹配其前面的字符的次数
*匹配任意次,可以是0次或多次
.*匹配任意长度的任意字符
\?匹配0次或1次
\{m\}匹配m次
\{m,n\}最少匹配m次,最多匹配n次
\{m,\}最少匹配m次
\{0,n\}最多匹配n次;
位置锚定:用于指定字符出现的位置
^锚定行首(^char)
$锚定行尾(char$)
^$空白行
\<锚定词首也可以用(\<char或\bchar)
\>锚定词尾也可以用(char\>char\b)
分组:
\(\)
引用:
\1后向引用,引用前面的第一个左括号以及与之对应的右括号中的模式所匹配到的内容
\2
...
He like his lover.
She love her liker.
He love his lover.
She like her liker.
grep "\(l..e\).*\1" test.txt
He love his lover.
She like her liker.
练习:
1、显示/proc/meminfo文件中以大小写s开头的行;
# grep "^[sS]" /proc/meminfo
# grep -i "^s" /proc/meminfo
2、取出默认shell为非bash的用户;
# grep -v "bash$" /etc/passwd | cut -d: -f1
3、取出默认shell为bash的且其ID号最大的用户;
# grep "bash$" /etc/passwd | sort -n -t: -k3 | tail -1 | cut -d: -f1
4、显示/etc/rc.d/rc.sysinit文件中,以#开头,后面跟至少一个空白字符,而后又有至少一个非空白字符的行;
# grep "^#[[:space:]]\{1,\}[^[:space:]]\{1,\}" /etc/rc.d/rc.sysinit
5、显示/boot/grub/grub.conf中以至少一个空白字符开头的行;
# grep "^[[:space:]]\{1,\}[^[:space:]]\{1,\}" /boot/grub/grub.conf
6、找出/etc/passwd文件中一位数或两位数;
# grep --color=auto "\<[0-9]\{1,2\}\>" /etc/passwd
7、找出ifconfig命令结果中的1到255之间的整数;
# ifconfig | grep -E --color=auto "\<([1-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\>"
8、查看当前系统上root用户的所有信息;
# grep "^root\>" /etc/passwd
9、添加用户bash和testbash、basher,而后找出当前系统上其用户名和默认shell相同的用户;
# grep --color=auto "^\([[:alnum:]]\{1,\}\)\>.*\1$" /etc/passwd
10、找出netstat -tan命令执行的结果中以“LISTEN”或“ESTABLISHED”结尾的行;
# netstat -tan | egrep "(LISTEN|ESTABLISHED)[[:space:]]+"
11、取出当前系统上所有用户的shell,要求:每种shell只显示一次,且按升序显示;
# cut -d: -f7 /etc/passwd | sort -u
挑战题:写一个模式,能匹配真正意义上的IP地址;(1.0.0.1--223.255.255.254)
egrep: 使用扩展正则表达来构建模式,相当于grep -E
字符匹配:
.匹配任意单个字符
[]匹配指定范围内的任意单个字符
[^]匹配指定范围外的任意单个字符
次数匹配:
*匹配任意次,可以是0次或多次 .*匹配任意长度的任意字符 ?匹配0次或1次
+匹配其前面的字符至少1次 {m}匹配m次 {m,n}最少匹配m次,最多匹配n次 {m,}最少匹配m次 {0,n}最多匹配n次;
锚定:
^锚定行首(^char)
$锚定行尾(char$)
^$空白行
\<锚定词首也可以用(\<char或\bchar
\>锚定词尾也可以用(char\>char\b)
分组:
()分组
| conC|cat的结果为conC或cat;con(C|c)at的结果为conCat或concat
引用:
\1向引用,引用前面的第一个左括号以及与之对应的右括号中的模式所匹配到的内容 \2 ...
练习:写一个脚本,分别统计/etc/rc.d/rc.sysinit、/etc/init.d/functions和/etc/fstab文件中各自以#开头的行的行数,以及空白行的行数;
#!/bin/bash
for fileName in /etc/rc.d/rc.sysinit /etc/init.d/functions /etc/fstab
do
line1=`egrep "^#" $fileName | wc -l`
line2=`egrep "^$" $fileName | wc -l`
echo "$fileName #:$line1 space:$line2"
done
练习:写一个脚本,分别复制/etc/rc.d/rc.sysinit、/etc/init.d/functions和/etc/fstab文件至/tmp目录中,文件名为原名后跟上当前的日期组成;
例如第一个文件复制后的名称为/tmp/rc.sysinit-2014-02-16;
#!/bin/bash
for fileName in /etc/rc.d/rc.sysinit /etc/init.d/functions /etc/fstab
do
cp $fileName /tmp/`basename $fileName`-`date "+%F"`
done
练习:写一个脚本
显示当前系统上所有默认shell为bash的用户的用户名、UID以及其在/etc/passwd文件中的行号;
#!/bin/bash
for userName in `grep "bash$" /etc/passwd | cut -d: -f1`
do
lineNum=`cat -n /etc/passwd | egrep "[[:space:]]+$userName" | egrep -o "[0-9]+[[:space:]]+"`
userId=`egrep "^$userName" /etc/passwd | cut -d: -f3`
echo "$lineNum $userName $userId"
done
bash编程之条件判断:判定后续操作的前提条件是否满足。
条件判断的常用测试类型:
整数测试
字符测试
文件测试
bash中如何做测试:
test EXPRESSION
[ EXPRESSION ]
` EXPRESSION `
bash中条件判断使用if:
单分支:
if 条件; then
分支1;
fi
双分支:
if 条件; then
分支1;
else
分支2;
fi
多分支:
if 条件1; then
分支1;
elif 条件2; then
分支2;
elif 条件3; then
分支3;
...
else
分支n;
fi
如果文件有空白行,就显示空白行数;否则,就说明文件无空白行;
#!/bin/bash
#
read -p "Enter a file path: " fileName
if grep "^$" $fileName &> /dev/null; then
linesCount=`grep "^$" $fileName | wc -l`
echo "$fileName has $linesCount space lines."
else
echo "$fileName hava no space line."
fi
bash编程之:整数测试
二元测试:
num1 OPRAND num2
-gt: 大于[ $num1 -gt $num2 ]
-lt: 小于
-ge:大于等于
-le: 小于等于
-ne: 不等于
-eq: 等于
bash知识点之脚本自定义退出:
exit [n]
练习:判定两个数孰大孰小,整数是通过命令行参数传递而来。
#!/bin/bash
#
if [ $# -lt 2 ]; then
echo "Stupid..."
echo "Usage: `basename $0` argu1 argu2"
exit 4
fi
if [ $1 -gt $2 ]; then
echo "The max num is $1."
else
echo "The max num is $2."
fi
bash知识点:只要命令用作条件,就表示引用是其状态结果(即执行成功与否),而非命令的输出结果,因此,不能使用命令替换符;
grep "^root\>" /etc/passwd
id root
练习:写一脚本,实现如下功能:
1、让用户通过键盘输入一个用户名
2、如果用户存在,就显示其用户名和UID;
3、否则,就显示用户不存在;
#!/bin/bash
read -t 10 -p "Enter a username: " userName
# userName=${userName:-root}
if id $userName &> /dev/null; then
userID=`id -u $userName`
echo "$userName: $userID"
else
echo "$userName not exist."
fi
练习:写一脚本,实现如下功能:
1、让用户通过键盘输入一个用户名,如果用户不存在就退出;
2、如果用户的UID大于等于500,就说明它是普通用户;
3、否则,就说明这是管理员或系统用户;
#!/bin/bash
# exit 6 --
read -t 10 -p "Enter a username: " userName
if ! id $userName &> /dev/null; then
echo "$userName not exist."
exit 6
fi
userID=`id -u $userName`
if [ $userID -ge 500 ]; then
echo "A common user."
else
echo "Admin or System user."
fi
bash的知识点:
组合条件测试:对条件做逻辑运算
与:条件1 && 条件2
条件1为假,则最终结果一定为假,因此,条件2将不执行;
条件1为真,则最终结果决于后面条件,因此,条件2必须执行;
或:条件1 || 条件2
条件1为真,则最终结果一定为真,因此,条件2将不再执行;
条件1为假,则最终结果决于后面条件,因此,条件2必须执行;
非: ! 条件
练习:写一脚本,实现如下功能:
1、让用户通过键盘输入一个用户名,如果用户不存在就退出;
2、如果其UID等于其GID,就说它是个"good guy"
3、否则,就说它是个“bad guy”;
#!/bin/bash
# exit 6 --
read -t 10 -p "Enter a username: " userName
if ! id $userName &> /dev/null; then
echo "$userName not exist."
exit 6
fi
if [ `id -u $userName` -eq `id -g $userName` ]; then
echo "Good guy."
else
echo "Bad guy."
fi
扩展:判断当前系统上的所有用户是Good guy还是Bad guy.
for userName in `cut -d: -f1 /etc/passwd`; do
done
练习:写一个脚本,实现如下功能:
1、添加10个用户stu1-stu10;但要先判断用户是否存在;
2、如果存在,就用红色显示其已经存在
3、否则,就添加此用户;并绿色显示;
4、最后显示一共添加了几个用户;
#!/bin/bash
#
declare -i userCount=0
for i in {1..10}; do
if id stu$i &> /dev/null; then
echo -e "\033[31mstu$i\033[0m exists."
else
useradd stu$i && echo -e "add \033[32mstu$i\033[0m finished."
let userCount++
fi
done
echo "Add $userCount users."
练习:求200以内所有3的整数倍的正整数的和;
#!/bin/bash
declare -i sum=0
for i in {1..200}; do
if [ $[$i%3] -eq 0 ]; then
let sum+=$i
fi
done
echo "The sum is: $sum."
grep [optinos] "pattern" file...
基本:
字符匹配:.,[][^]
次数匹配:*,\?,\{m\},\{m,n\}
位置锚定:\<,\b,\>,^,$
分组:\(\)
前向引用:\1,\2
扩展:
字符匹配:.,[][^]
次数匹配:*,?,{m},{m,n},+
位置锚定:\<,\b,\>,^,$
分组:()
前向引用:\1,\2
或a|b
条件判断
if condition;then
statement1
....
fi
if condition;then
分支1;
else
分支2;
fi
if condition;then
分支1;
elif condition;then
分支2;
...
else
分支n;
fi
条件测试:
bash :每个命令,执行状态都有返回值
成功:0
失败:非0
$?
脚本的状态返回值:脚本执行的最后一条命令:
自定义脚本状态返回值:exit[n]
引用命令的执行结果:使用`command`或$(command)
引用命令执行成功与否的状态结果:一定是直接执行命令。此时,通常需要将执行结果重定向至/dev/null
条件测试:
test 测试表达式
[ 测试表达式 ]
[[]]:bash中的关键字
bash的知识点:
组合条件测试:对条件做逻辑运算
与:条件1 &&条件2
条件1为假,则最终结果一定为假,因此,条件2不予执行
条件1为真,则最终条件结果决于后面条件,因此,条件2必须执行
或:
条件1为真,则最终结果一定为真,因此,条件2不予执行
条件1为假,则最终条件结果决于后面条件,因此,条件2必须执行
非:
与的优先级大于或,或的优先级大于非
本文转自开源殿堂 51CTO博客,原文链接:http://blog.51cto.com/kaiyuandiantang/1936647,如需转载请自行联系原作者