设X小于Y小于O,求证x方+a大于小于y方...

vivo Xplay3S(X520L/移动4G)
vivo Xplay3S(X520L/移动4G) 别名:xplay 2,Xplay 3S,X520L2K屏幕,指纹识别,HiFi音效
>> PART:DetailVer3/Part/Detail/FirstScreen >>> -->
本地服务:
合约购机:
1288人评分
>> PART:DetailVer3/Part/Detail/ParamPerformance >>> -->
屏幕清晰度
摄像头像素
在2954款智能手机中,该主屏尺寸大于95%的手机
6英寸:介于平板与手机之间的跨界产品,不建议单手操作,携带时适合带包人群
6英寸:介于平板与手机之间的跨界产品,不建议单手操作,携带时适合带包人群
3.94mm:极窄边框,触屏手机的最佳配置范围,既提高了屏幕占比,又可以作为保护边框增强屏幕的抗摔性
在2954款智能手机中,该屏幕清晰度大于96%的手机
490ppi:具备较高屏幕显示效果,高端机型或屏幕为主卖点必备要素
在2954款智能手机中,该电池容量大于84%的手机
3200mAh:电池续航时间,需要结合使用频率、屏幕材质、屏幕大小、系统设置等多方面衡量
在2954款智能手机中,该摄像头像素大于54%的手机
在2954款智能手机中,该摄像头像素大于52%的手机
1300万像素:中高端级别摄像头像素,有较好的成像效果,逐渐成为大众化配置
RAM为运行内存,RAM的大小直接决定了你在手机后台能开多少程序。
ROM为机身存储,ROM的大小决定了你能在手机中安装多少程序,存放多少歌曲、电影、小说。
3G时代需占用更多系统空间,提升RAM运行速度更快
中低端机器的配置。如果储存信息过多会造成卡顿现象
该产品暂无此项性能得分
该产品暂无此项性能得分
该产品暂无此项性能得分
在2954款智能手机中,该性能测试大于90%的手机
在2954款智能手机中,该性能测试大于99%的手机
安兔兔综合性能得分
vellamo网页浏览性能得分
*同价位竞品手机排名
>> PART:DetailVer3/Part/Detail/ExtraPrice >>> -->
显示厂商指导价
vivo Xplay3S 全部型号
商家最低价
& 2498[北京 停产 ]厂商指导价
& 1649[北京 停产 ]
商家最低价
& 1699[北京 停产 ]
暂无相关产品
>> PART:DetailVer3/Part/Detail/RelDocV31 >>> -->
元宵节不愁拍这8部手机照片&诱色可餐&元宵节马上就要到了,相信又有一些小伙伴一定觉得年没过瘾,想继续约朋友一起&吃吃吃&,而这估计也是过年中最后的&狂晒朋友圈&机会,...
vivoX7全新自拍神器特别邀请老公宋仲基代言,镜头加入Moonlight柔光灯,仿真摄影棚苹果光,让你的皮肤红润有光泽,肤色更均匀,美丽就像在发光。使用1600w前置拍照传感器,...
(中关村在线内蒙古行情)vivoX6SPlus
搭载vivo和Cirrus Logic定制DAC芯片CS4398,配以专业运放芯片AD45257,驱动能力强,瞬态响应好...
>> PART:DetailVer3/Part/Detail/EvaPic >>> -->
>> PART:DetailVer3/Part/Review/ReviewDetail >>> -->
1288人评分
您对该产品的感受,分享更多内容可选择高级点评
您的点评很用心,去写
>> PART:DetailVer3/Part/AskBbs/AskBbs >>> -->
昨天快递小哥送来了N个快递,其中vivo Xplay3S 是等了好久的。从vivo Xplay3S 发布到昨天快递小哥送来了N个快递,其中vivo Xplay3S 是等了好久的。从vivo Xplay3S 发布到...
浏览(175916)
2014年马上有新手机这个愿望简单易实现,而在2013年末 VIVO发布的新款手机vivo Xplay 2014年马上有新手机这个愿望简单易实现,而在2013年末 VIVO发布的新款手机vivo Xplay ...
浏览(78789)
常见问题:
&&& 综合对比两台手机,Vivo xplay3s的硬件配置更出色,综合表现更优秀,可以更好地满足楼主的使用需要。
& & 楼主你好,这个是同一款手机,只是称呼不同而已,楼主可以放心。
该问题还没有人回答,点击“我来回答”,就有机会被采纳并得到相应悬赏奖励。
楼主你好!& & 检测机器是否ROOT,如果ROOT,可能对手机系统造成影响,导致升级不成功,请尝试取下电池断电一会再开机试下,如果不能正常开机,只能够...
LV2 编辑专家
& & 楼主你好,Xplay3S推出的时间并不算长,所以降价的可能性并不高。
& & 设置--安全和隐私--隐私保护即可设置相关程序
[ 停产 2016-0...]
[64GB厂商指导价]
小提示:可以选择产品进行切换哦
OPPO R9s(全网通)
正在进行PK
[64GB厂...]
一加手机3T(全网通)
正在进行PK
[64GB行...]
华为Mate 8(NXT-AL10/3GB RAM/全网通)
正在进行PK
[32GB行...]
vivo X7(全网通)
正在进行PK
[64GB厂...]
华为P9(EVA-AL10/高配版/全网通)
正在进行PK
[64GB行...]
[ 停产 2016-0...]
[64GB行货]
小提示:可以选择产品进行切换哦
华为Mate 9(MHA-AL00/4GB RAM/全网通)
正在进行PK
[64GB行...]
vivo X9Plus(全网通)
正在进行PK
[64GB厂...]
华为Mate 8(NXT-AL10/3GB RAM/全网通)
正在进行PK
[32GB行...]
OPPO R9s Plus(全网通)
正在进行PK
[64GB厂...]
乐视乐Max 2(6GB RAM/全网通)
正在进行PK
[64GB行...]
与其他产品进行PK:
>> PART:DetailVer3/Part/Detail/RelPros >>> -->
>> PART:DetailVer3/Part/Detail/Drive >>> -->
>> PART:DetailVer3/Part/Detail/PossibleInterest >>> -->
同系列,同品牌
月销量2314
同品牌,同CPU频率
同后置摄像头
月销量3546
同品牌,同存储卡
同价位,同品牌
同价位,同后置摄像头
同品牌,同存储卡
同价位,同品牌
>> PART:PluginVer3/Rank/Manu >>> -->
>> PART:PluginVer3/Rank/Pro >>> -->
>> PART:DetailVer3/Part/Detail/AdZPlusGoods >>> -->
>> PART:DetailVer3/Part/Detail/LastProTbl >>> -->
>> PART:PluginVer3/Rank/Pro >>> -->
>> PART:DetailVer3/Part/Detail/AboutManu >>> -->
联系电话:400-678-9688
官方网站:
联系地址:东莞市长安镇乌沙步步高大道23号
电子邮件:下载作业帮安装包
扫二维码下载作业帮
1.75亿学生的选择
已知圆x^2+y^2+x+2y=61/16,圆(x-sina)^2+(y-1)^2=1/16,其中a大于等于0度,小于等于90度,求两圆的位置
解智先xKX3
设圆O:x^2+y^2+x+2y=61/16,(x^2+x+1/4)+(y^2+2y+1)=81/16,(x+1/2)^2+(y+1)^2=(9/4)^2圆P:(x-sinα)^2+(y-1)^2=(1/4)^2∴圆O的圆心为(-1/2,-1),半径为9/4;圆P的圆心为(sinα,1),半径为1/4两圆的圆心距d为√[(sinα+(1/2))^2+(1+1)^2]=√[(sinα+(1/2))^2+4]圆O和圆P的半径r1、r2分别是9/4、1/4∵0≤α≤90° ∴0≤sinα≤1,1/2≤sinα+(1/2)≤3/2,1/4≤(sinα+(1/2))^2≤9/4∴17/4≤(sinα+(1/2))^2+4≤25/4,|r1-r2|=9/4-1/4=2=4/2=(√16)/2<(√17)/2≤d≤5/4<10/4=9/4+1/4=r1+r2∴|r1-r2|<d<r1+r2 ∴两圆相交
为您推荐:
其他类似问题
扫描下载二维码欢迎来到慢慢买! &
扫描二维码下载客户端
慢慢买客户端
A.O.史密斯(A.O.Smith) JSQ33-N3L(X) 16升/min 电脑板燃气热水器
价格区间:¥5848至¥6498
优选评价:4.9分
全网共有 7307 人评论 &
& 类目排名第
品牌:上市时间:2014年03月热水器类型:燃气热水器热水器款式:立式热水器(竖式)控制方式:微电脑式能效等级:二级能效
为了更准确的显示价格和是否有货信息,请设置收货地址
【新春开门红!5848元钜惠来袭!买即享200元材料费抵用券 防煤气中毒报警器!晒单更赠双立人套刀!晒单后联系客服登记!下单前咨询加赠延保金卡!】143年创新精品!专利智能静音技术,40分贝疗养院级静音标准!
AO史密斯官方旗舰店
智能静音!专利CO防护!智能双宽频恒温!
A.O.史密斯官方旗舰店
【咨询客服领取200元安装材费抵扣券!】【智能恒温静音】下单送双立人刀具+浴巾五件套+延保金卡!适合中国用户的热水器>>>
A.O.史密斯官方旗舰店
A.O.史密斯(A.O.Smith) JSQ33-N3L(X) 16升/min 电脑板燃气热水器怎么样?看看下面购买过的网友怎么说!
2154人参与评分
购买过此商品?
购买自【】
购买自【】
购买自【】
购买自【】
购买自【】
购买自【】
购买自【】
购买自【】
购买自【】
购买自【】
跳转到&&页
和A.O.史密斯JSQ33-N3L同类商品推荐
最低¥3198 最低¥4198 最低¥3599 最低¥1899 最低¥3578 最低¥1799 最低¥2299 最低¥3499 最低¥1499 最低¥5038 最低¥4698 最低¥3399
最低价:¥3398
最低价:¥3598
最低价:¥4978
最低价:¥3058
最低价:¥3578
最低价:¥3799
最低价:¥4580
最低价:¥3180
最低价:¥3499
最低价:¥4880
1 2 3 4 5 6 7 8 9 10
最低价:¥1099
最低价:¥698
最低价:¥999
最低价:¥318
最低价:¥3198
5秒注册就能立刻拿返利
本站支持京东、国美、苏宁、卓越网、库巴、新蛋等12家商城的返利
扫描下载慢慢买APP
全网比价 省钱专家第5章 习题解答_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
第5章 习题解答
上传于||暂无简介
阅读已结束,如果下载本文需要使用0下载券
想免费下载更多文档?
定制HR最喜欢的简历
下载文档到电脑,查找使用更方便
还剩6页未读,继续阅读
定制HR最喜欢的简历
你可能喜欢8866人阅读
linux(2)
一.&& &特殊文件: /dev/null和/dev/tty
&& &Linux系统提供了两个对Shell编程非常有用的特殊文件,/dev/null和/dev/tty。其中/dev/null将会丢掉所有写入它的数据,换句换说,当程序将数据写入到此文件时,会认为它已经成功完成写入数据的操作,但实际上什么事都没有做。如果你需要的是命令的退出状态,而非它的输出,此功能会非常有用,见如下Shell代码:
&& &/& vi test_dev_null.sh
&& &#!/bin/bash
&& &if grep hello TestFile & /dev/null
&& &&&& echo &Found&
&& &&&& echo &NOT Found&
&& &在vi中保存并退出后执行以下命令:
&& &/& chmod +x test_dev_null.sh& #使该文件成为可执行文件
&& &/& cat & TestFile
&& &hello my friend
&& &CTRL + D&&&&&&&&&&&&&&&&&&&&&&&&&&&& #退出命令行文件编辑状态
&& &/& ./test_dev_null.sh
&& &Found&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& #这里并没有输出grep命令的执行结果。
&& &将以上Shell脚本做如下修改:
&& &/& vi test_dev_null.sh
&& &#!/bin/bash
&& &if grep hello TestFile
&& &&&& echo &Found&
&& &&&& echo &NOT Found&
&& &在vi中保存退出后,再次执行该脚本:
&& &/& ./test_dev_null.sh
&& &hello my friend&&&&&&&&&&&&&&&&&&&&& #grep命令的执行结果被输出了。
&& &下面我们再来看/dev/tty的用途。当程序打开此文件是,Linux会自动将它重定向到一个终端窗口,因此该文件对于读取人工输入时特别有用。见如下Shell代码:
&& &/& vi test_dev_tty.sh
&&& #!/bin/bash
&& &printf &Enter new password: &&& &#提示输入
&& &stty -echo&& &&& &&& &&& &&& &&& &&&&&&& #关闭自动打印输入字符的功能
&& &read password & /dev/tty&& &&& & #读取密码
&& &printf &\nEnter again: &&& &&& &&&&& #换行后提示再输入一次
&& &read password2 & /dev/tty&& &&& #再读取一次以确认
&& &printf &\n&&& &&& &&& &&& &&& &&& &&&&&&& #换行
&& &stty echo&& &&& &&& &&& &&& &&& &&&&&&&& #记着打开自动打印输入字符的功能
&& &echo &Password = & $password #输出读入变量
&& &echo &Password2 = & $password2
&& &echo &All Done&
&&& 在vi中保存并退出后执行以下命令:
&& &/& chmod +x test_dev_tty.sh #使该文件成为可执行文件
&& &/& ./test_dev_tty
&& &Enter new password:&&&&&&&&&&&& #这里密码的输入被读入到脚本中的password变量
&& &Enter again:&&&&&&&&&&&&&&&&&&&&&&&&& #这里密码的输入被读入到脚本中的password2变量
&& &Password = hello
&& &Password2 = hello
&& &All Done
二.&& &简单的命令跟踪:
&& &Linux Shell提供了两种方式来跟踪Shell脚本中的命令,以帮助我们准确的定位程序中存在的问题。下面的代码为第一种方式,该方式会将Shell脚本中所有被执行的命令打印到终端,并在命令前加&+&:加号的后面还跟着一个空格。
&& &/& cat & trace_all_command.sh
&& &who | wc -l&&&&&&&&&&&&&&&&&&&&&&&&& #这两条Shell命令将输出当前Linux服务器登录的用户数量
&& &CTRL + D&&&&&&&&&&&&&&&&&&&&&&&&&&& #退出命令行文件编辑状态
&& &/& chmod +x trace_all_command.sh
&& &/& sh -x ./trace_all_command.sh #Shell执行器的-x选项将打开脚本的执行跟踪功能。
&& &+ wc -l&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& #被跟踪的两条Shell命令
&& &+ who
&& &2&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& #实际输出结果。
&& &Linux Shell提供的另一种方式可以只打印部分被执行的Shell命令,该方法在调试较为复杂的脚本时,显得尤为有用。
&& &/& cat & trace_patial_command.sh
&& &#! /bin/bash
&& &set -x&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& #从该命令之后打开跟踪功能
&& &echo 1st echo&&&&&&&&&&&&&&&&&&&& #将被打印输出的Shell命令
&& &set +x&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& #该Shell命令也将被打印输出,然而在该命令被执行之后,所有的命令将不再打印输出
&&& echo 2nd echo&&&&&&&&&&&&&&&&&&& #该Shell命令将不再被打印输出。
&&& CTRL + D&& &&&&&&&&&&&&&&&&&&&&&&& #退出命令行文件编辑状态
&&& /& chmod +x trace_patial_command.sh
&&& /& ./trace_patial_command.sh
&&& + echo 1st echo
&&& 1st echo
&&& + set +x
&&& 2nd echo
三.&& &正则表达式基本语法描述:
&& &Linux Shell环境下提供了两种正则表达式规则,一个是基本正则表达式(BRE),另一个是扩展正则表达式(ERE)。
&& &下面是这两种表达式的语法列表,需要注意的是,如果没有明确指出的Meta字符,其将可同时用于BRE和ERE,否则将尽适用于指定的模式。
正则元字符
通常用于关闭其后续字符的特殊意义,恢复其原意。
\(...\),这里的括号仅仅表示括号。
匹配任何单个字符。
a.b,将匹配abb、acb等
匹配它之前的0-n个的单个字符。
a*b,将匹配ab、aab、aaab等。
匹配紧接着的正则表达式,在行的起始处。
^ab,将匹配abc、abd等,但是不匹配cab。
匹配紧接着的正则表达式,在行的结尾处。
ab$,将匹配ab、cab等,但是不匹配abc。
方括号表达式,匹配其内部任何字符。其中-表示连续字符的范围,^符号置于方括号里第一个字符则有反向的含义,即匹配不在列表内(方括号)的任何字符。如果想让]和-表示其原意,需要将其放置在方括号的首字符位置,如[]ab]或[-ab],如这两个字符同时存在,则将]放置在首字符位置,-放置在最尾部,如[]ab-]。
[a-bA-Z0-9!]表示所有的大小写字母,数字和感叹号。[^abc]表示a、b、c之外的所有字符。[Tt]om,可以匹配Tom和tom。
区间表达式,匹配在它前面的单个字符重复出现的次数区间,\{n\}表示重复n次;\{n,\}表示至少重复n次;\{n,m\}表示重复n到m次。
ab\{2\}表示abb;ab\{2,\}表示abb、abbb等。ab\{2,4\}表示abb、abbb和abbbb。
将圆括号之间的模式存储在特殊“保留空间”。最多可以将9个独立的子模式存储在单个模式中。匹配于子模式的文本,可以通过转义序列\1到\9,被重复使用在相同模式里。
\(ab\).*\1表示ab组合出现两次,两次之间可存在任何数目的任何字符,如abcdab、abab等。
{n,m}(ERE)
其功能等同于上面的\{n,m\},只是不再写\转义符了。
ab+匹配ab、abbb等,但是不匹配a。
+(ERE)
和前面的星号相比,+匹配的是前面正则表达式的1-n个实例。
匹配前面正则表达式的0个或1个。
ab?仅匹配a或ab。
匹配于|符号前后的正则表达式。
(ab|cd)匹配ab或cd。
匹配字母字符。
[[:alpha:]!]ab$匹配cab、dab和!ab。
匹配字母和数字字符。
[[:alnum:]]ab$匹配1ab、aab。
匹配空格(space)和Tab字符。
[[:alnum:]]ab$匹配1ab、aab。
匹配控制字符。
匹配数字字符。
匹配非空格字符。
匹配小写字母字符。
匹配大写字母字符。
匹配标点字符。
匹配空白(whitespace)字符。
[:xdigit:]
匹配十六进制数字。
匹配任何字母和数字组成的字符,等同于[[:alnum:]_]
匹配任何非字母和数字组成的字符,等同于[^[:alnum:]_]
匹配单词的起始和结尾。
\&read匹配readme,me\&匹配readme。
&& &下面的列表给出了Linux Shell中常用的工具或命令分别支持的正则表达式的类型。
四.&& &使用cut命令选定字段:
&& &cut命令是用来剪下文本文件里的数据,文本文件可以是字段类型或是字符类型。下面给出应用实例:
&&& /& cat /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
&& &adm:x:3:4:adm:/var/adm:/sbin/nologin
&& &... ...
&&& /& cut -d : -f 1,5 /etc/passwd&&&& #-d后面的冒号表示字段之间的分隔符,-f表示取分割后的哪些字段
&& &root:root&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& #这里取出的是第一个和第五个字段。
&& &bin:bin
&& &daemon:daemon
&& &adm:adm
&& &... ...
&&& /&cut -d: -f 3- /etc/passwd&&&&&& #从第三个字段开始显示,直到最后一个字段。
&&& 0:0:root:/root:/bin/bash
&&& 1:1:bin:/bin:/sbin/nologin
&&& 2:2:daemon:/sbin:/sbin/nologin
&&& 3:4:adm:/var/adm:/sbin/nologin
&&& 4:7:lp:/var/spool/lpd:/sbin/nologin
&&& ... ...&& &
&& &这里需要进一步说明的是,使用cut命令还可以剪切以字符数量为标量的部分字符,该功能通过-c选项实现,其不能与-d选项共存。
&&& /& cut -c 1-4 /etc/passwd&&&&&&&&& #取每行的前1-4个字符。
&&& /& cut -c-4 /etc/passwd&&&&&&&&&&& #取每行的前4个字符。
&&& ... ...
&&& /& cut -c4- /etc/passwd&&&&&&&&&&& #取每行的第4个到最后字符。
&& &t:x:0:0:root:/root:/bin/bash
&& &:x:1:1:bin:/bin:/sbin/nologin
&& &mon:x:2:2:daemon:/sbin:/sbin/nologin
&& &:x:3:4:adm:/var/adm:/sbin/nologin
&&& ... ...
&&& /& cut -c1,4 /etc/passwd&&&&&&&&&& #取每行的第一个和第四个字符。
&& &... ...
&&& /& cut -c1-4,5 /etc/passwd&&&&&&& #取每行的1-4和第5个字符。
五.&& &计算行数、字数以及字符数:
&& &Linux提供了一个简单的工具wc用于完成该功能,见如下用例:
&&& /& echo This is a test of the emergency broadcast system | wc
&& &1&& &9&& &49&&&&&&&&&&&&&&&&&&&&&&&&&&&&& #1行,9个单词,49个字符
&&& /& echo Testing one two three | wc -c
&& &22&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& #22个字符
&&& /& echo Testing one two three | wc -l
&& &1&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& #1行
&&& /& echo Testing one two three | wc -w
&& &4&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& #4个单词
&&& /& wc /etc/passwd /etc/group&&& #计算两个文件里的数据。
&& &39&& 71& 1933& /etc/passwd
& & 62&& 62& 906&&& /etc/group
&& &101 133 2839& 总用量
六.&& &提取开头或结尾数行:
&& &有时,你会需要从文本文件里把几行字,多半是靠近开头或结尾的几行提取出来。如查看工作日志等操作。Linux Shell提供head和tail两个命令来完成此项工作。见如下用例:
&&& /& head -n 5 /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
&& &adm:x:3:4:adm:/var/adm:/sbin/nologin
&& &lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
&&& /& tail -n 5 /etc/passwd&&&&&&&&&&&& #显示输入文件的最后五行。
&& &sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
&& &mysql:x:27:27:MySQL Server:/var/lib/mysql:/bin/bash
&& &pulse:x:496:494:PulseAudio System Daemon:/var/run/pulse:/sbin/nologin
&& &gdm:x:42:42::/var/lib/gdm:/sbin/nologin
&& &stephen:x:500:500:stephen:/home/stephen:/bin/bash
&& &如果使用者想查看不间断增长的日志(如服务程序输出的),可以使用tail的-f选项,这样可以让tail命令不会自动退出,必须通过CTRL+C命令强制退出,因此该选项不适合用于Shell脚本中,见如下用例:
&&& /& tail -f -n 5 my_server_log
&& &... ...
&& &^C&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& #CTRL+C退出到命令行提示符状态。
七、非直接引用变量:
&& && 在Shell中提供了三种为标准(直接)变量赋值的方式:
&& && 1. 直接赋值。
&& && 2. 存储一个命令的输出。
&& && 3. 存储某类型计算的结果。
&& && 然而这三种方式都是给已知变量名的变量赋值,如name=Stephen。但是在有些情况下,变量名本身就是动态的,需要依照运行的结果来构造变量名,之后才是为该变量赋值。这种变量被成为动态变量,或非直接变量。
&& && /& cat & test7.sh
&& && #!/bin/sh
&& && work_dir=`pwd`
&& && #1. 由于变量名中不能存在反斜杠,因此这里需要将其替换为下划线。
&& && #2. work_dir和file_count两个变量的变量值用于构建动态变量的变量名。
&& && work_dir=`echo $work_dir | sed 's/\//_/g'`
&& && file_count=`ls | wc -l`
&& && #3. 输出work_dir和file_count两个变量的值,以便确认这里的输出结果和后面构建的命令名一致。
&& && echo &work_dir = & $work_dir
&& && echo &file_count = & $file_count
& & & #4. 通过eval命令进行评估,将变量名展开,如${work_dir}和$file_count,并用其值将其替换,如果不使用eval命令,将不会完成这些展开和替换的操作。最后为动态变量赋值。
& & & eval BASE${work_dir}_$file_count=$(ls $(pwd) | wc -l)
& & & #5. 先将echo命令后面用双引号扩住的部分进行展开和替换,由于是在双引号内,仅完成展开和替换操作即可。
& & & #6. echo命令后面的参数部分,先进行展开和替换,使其成为$BASE_root_test_1动态变量,之后在用该变量的值替换该变量本身作为结果输出。
& & & eval echo &BASE${work_dir}_$file_count = & '$BASE'${work_dir}_$file_count
& & & CTRL+D
&& && /& . ./test7.sh
& & & work_dir =& _root_test
& & & file_count =& 1
& & & BASE_root_test_1 = 1
八、在循环中使用管道的技巧:
&& && 在Bash Shell中,管道的最后一个命令都是在子Shell中执行的。这意味着在子Shell中赋值的变量对父Shell是无效的。所以当我们将管道输出传送到一个循环结构,填入随后将要使用的变量,那么就会产生很多问题。一旦循环完成,其所依赖的变量就不存在了。
& & & /& cat & test8_1.sh
&& && #!/bin/sh
&& && #1. 先将ls -l命令的结果通过管道传给grep命令作为管道输入。
&& && #2. grep命令过滤掉包含total的行,之后再通过管道将数据传给while循环。
&& && #3. while read line命令从grep的输出中读取数据。注意,while是管道的最后一个命令,将在子Shell中运行。
&& && ls -l | grep -v total | while read line
&& & && & #4. all变量是在while块内声明并赋值的。
&&& && && all=&$all $line&
&& && &&& echo $line
& & & done
& & & #5. 由于上面的all变量在while内声明并初始化,而while内的命令都是在子Shell中运行,包括all变量的赋值,因此该变量的值将不会传递到while块外,因为块外地命令是它的父Shell中执行。
& & & echo &all = & $all
& & & CTRL+D
& & & /& ./test8_1.sh
& & & -rw-r--r--.& 1 root root 193 Nov 24 11:25 outfile
& & & -rwxr-xr-x. 1 root root 284 Nov 24 10:01 test7.sh
& & & -rwxr-xr-x. 1 root root 108 Nov 24 12:48 test8_1.sh
& & & all =
& & & 为了解决该问题,我们可以将while之前的命令结果先输出到一个临时文件,之后再将该临时文件作为while的重定向输入,这样while内部和外部的命令都将在同一个Shell内完成。
& & & /& cat & test8_2.sh
& & & #!/bin/sh
& & & #1. 这里我们已经将命令的结果重定向到一个临时文件中。
& & & ls -l | grep -v total & outfile
& & & while read line
& && &&&& #2. all变量是在while块内声明并赋值的。
& && &&&& all=&$all $line&
&& && &&& echo $line
&& && &&& #3. 通过重定向输入的方式,将临时文件中的内容传递给while循环。
&& && done & outfile
& & & #4. 删除该临时文件。
& & & rm -f outfile
& & & #5. 在while块内声明和赋值的all变量,其值在循环外部仍然有效。
& & & echo &all = & $all
& & & CTRL+D
& & & /& ./test8_2.sh
& & & -rw-r--r--.& 1 root root&& 0 Nov 24 12:58 outfile
&& && -rwxr-xr-x. 1 root root 284 Nov 24 10:01 test7.sh
&& && -rwxr-xr-x. 1 root root 140 Nov 24 12:58 test8_2.sh
& & & all =& -rwxr-xr-x. 1 root root 284 Nov 24 10:01 test7.sh -rwxr-xr-x. 1 root root 135 Nov 24 13:16 test8_2.sh
&& && 上面的方法只是解决了该问题,然而却带来了一些新问题,比如临时文件的产生容易导致性能问题,以及在脚本异常退出时未能及时删除当前使用的临时文件,从而导致生成过多的垃圾文件等。下面将再介绍一种方法,该方法将同时解决以上两种方法同时存在的问题。该方法是通过HERE-Document的方式来替代之前的临时文件方法。
&& && /& cat & test8_3.sh
& & & #!/bin/sh
&& && #1. 将命令的结果传给一个变量&& &
&& && OUTFILE=`ls -l | grep -v total`
&& && while read line
& && &&&& all=&$all $line&
& && &&&& echo $line
& & & done &&EOF
& & & #2. 将该变量作为该循环的HERE文档输入。
& & & $OUTFILE
& & & #3. 在循环外部输出循环内声明并初始化的变量all的值。
& & & echo &all = & $all
& & & CTRL+D
& & & /& ./test8_3.sh
& & & -rwxr-xr-x. 1 root root 284 Nov 24 10:01 test7.sh
& & & -rwxr-xr-x. 1 root root 135 Nov 24 13:16 test8_3.sh
& & & all =& -rwxr-xr-x. 1 root root 284 Nov 24 10:01 test7.sh -rwxr-xr-x. 1 root root 135 Nov 24 13:16 test8_3.sh
九、自链接脚本:
&& && 通常而言,我们是通过脚本的命令行选项来确定脚本的不同行为,告诉它该如何操作。这里我们将介绍另外一种方式来完成类似的功能,即通过脚本的软连接名来帮助脚本决定其行为。
&& && /& cat & test9.sh
&& && #!/bin/sh
& & & #1. basename命令将剥离脚本的目录信息,只保留脚本名,从而确保在相对路径的模式下执行也没有任何差异。
& & & #2. 通过sed命令过滤掉脚本的扩展名。
& & & dowhat=`basename $0 | sed 's/\.sh//'`
& & & #3. 这里的case语句只是为了演示方便,因此模拟了应用场景,在实际应用中,可以为不同的分支执行不同的操作,或将某些变量初始化为不同的值和状态。
& & & case $dowhat in
& & & test9)
&& && &&& echo &I am test9.sh&
&& && &&& ;;
&& && test9_1)
&& & &&&& echo &I am test9_1.sh.&
&& & & && ;;
&& && test9_2)
&& &&&&&& echo &I am test9_2.sh.&
&& &&&&&& ;;
&& &&&&&& echo &You are illegal link file.&
&& &&&&&& ;;
&& && esac
&& && CTRL+D
&& && /& chmod a+x test9.sh
&& && /& ln -s test9.sh test9_1.sh
&& && /& ln -s test9.sh test9_2.sh
&& && /& ls -l
&& && lrwxrwxrwx. 1 root root&& 8 Nov 24 14:32 test9_1.sh -& test9.sh
&& && lrwxrwxrwx. 1 root root&& 8 Nov 24 14:32 test9_2.sh -& test9.sh
& & & -rwxr-xr-x. 1 root root 235 Nov 24 14:35 test9.sh
& & & /& ./test9.sh
& & & I am test9.sh.
& & & /& ./test9_1.sh
& & & I am test9_1.sh.
& & & /& ./test9_2.sh
&& && I am test9_2.sh.
十、Here文档的使用技巧:
&& && 在命令行交互模式下,我们通常希望能够直接输入更多的信息,以便当前的命令能够完成一定的自动化任务,特别是对于那些支持自定义脚本的命令来说,我们可以将脚本作为输入的一部分传递给该命令,以使其完成该自动化任务。
&& && #1. 通过sqlplus以dba的身份登录Oracle数据库服务器。
&& && #2. 在通过登录后,立即在sqlplus中执行oracle的脚本CreateMyTables和CreateMyViews。
&& && #3. 最后执行sqlplus的退出命令,退出sqlplus。自动化工作完成。
& & & /& sqlplus &/as sysdba& &&-SQL
& & & & @CreateMyTables
&& && & @CreateMyViews
&& && & exit
&& && & SQL
十一、获取进程的运行时长(单位: 分钟):
&& && 在进程监控脚本中,我们通常需要根据脚本的参数来确定有哪些性能参数将被收集,当这些性能参数大于最高阈值或小于最低阈值时,监控脚本将根据实际的情况,采取预置的措施,如邮件通知、直接杀死进程等,这里我们给出的例子是收集进程运行时长性能参数。
&& && ps命令的etime值将给出每个进程的运行时长,其格式主要为以下三种:
&& && 1. minutes:seconds,如20:30
&& && 2. hours:minutes:seconds,如1:20:30
&& && 3. days-hours:minute:seconds,如2-18:20:30
&& && 该脚本将会同时处理这三种格式的时间信息,并最终转换为进程所流经的分钟数。
&& && /& cat & test11.sh
&& && #!/bin/sh
&& && #1. 通过ps命令获取所有进程的pid、etime和comm数据。
&& && #2. 再通过grep命令过滤,只获取init进程的数据记录,这里我们可以根据需要替换为自己想要监控的进程名。
&& && #3. 输出结果通常为:1 09:42:09 init
&& && pid_string=`ps -eo pid,etime,comm | grep &init& | grep -v grep`
&& && #3. 从这一条记录信息中抽取出etime数据,即第二列的&#:09,并赋值给exec_time变量。
& & & exec_time=`echo $pid_string | awk '{print $2}'`
& & & #4. 获取exec_time变量的时间组成部分的数量,这里是3个部分,即时:分:秒,是上述格式中的第二种。
&& && time_field_count=`echo $exec_time | awk -F: '{print NF}'`
& & & #5. 从exec_time变量中直接提取分钟数,即倒数第二列的数据(42)。
& & & count_of_minutes=`echo $exec_time | awk -F: '{print $(NF-1)}'`
&& && #6. 判断当前exec_time变量存储的时间数据是属于以上哪种格式。
&& && #7. 如果是第一种,那么天数和小时数均为0。
&& && #8. 如果是后两种之一,则需要继续判断到底是第一种还是第二种,如果是第二种,其小时部分将不存在横线(-)分隔符分隔天数和小时数,否则需要将这两个时间字段继续拆分,以获取具体的天数和小时数。对于第二种,天数为0.
&& && if [ $time_field_count -lt 3 ]; then
&& && &&& count_of_hours=0
&& && &&& count_of_days=0
& & & else
&&& && && count_of_hours=`echo $exec_time | awk -F: '{print $(NF-2)}'`
&&& && && fields=`echo $count_of_hours | awk -F- '{print NF}'`
&&& && && if [ $fields -ne 1 ]; then
&&&& && &&&&& count_of_days=`echo $count_of_hours | awk -F- '{print $1}'`
&&&& && &&&&& count_of_hours=`echo $count_of_hours | awk -F- '{print $2}'`
&&&&& & & else
&&&&&& && &&& count_of_days=0
&&&&& & & fi
&& && #9. 通过之前代码获取的各个字段值,计算出该进程实际所流经的分钟数。
& & & #10. bc命令是计算器命令,可以将echo输出的数学表达式计算为最终的数字值。
& & & elapsed_minutes=`echo &$count_of_days*1440+$count_of_hours*60+$count_of_minutes& | bc`
& & & echo &The elapsed minutes of init process is& $elapsed_minutes &minutes.&
&&& & CTRL+D
& & & /& ./test11.sh
& & & The elapsed minutes of init process is 577 minutes.
十二、模拟简单的top命令:
&& && 这里用脚本实现了一个极为简单的top命令。为了演示方便,我们在脚本中将很多参数都写成硬代码,你可以根据需要更换这些参数,或者用更为灵活的方式替换现有的实现。
&& && /& cat & test12.sh
&& && #!/bin/sh
&& && #1. 将ps命令的title赋值给一个变量,这样在每次输出时,直接打印该变量即可。
&& && header=`ps aux | head -n 1`
& & & #2. 这里是一个无限循环,等价于while true
&& && #3. 每次循环先清屏,之后打印uptime命令的输出。
&& && #4. 输出ps的title。
&& && #5. 这里需要用sed命令删除ps的title行,以避免其参与sort命令的排序。
&& && #6. sort先基于CPU%倒排,再基于owner排序,最后基于pid排序,最后再将结果输出给head命令,仅显示前20行的数据。
&& && #7. 每次等待5秒后刷新一次。
& && while :
&&&&& & & clear
&&&&&&&&& uptime
&&&&&&&&& echo &$header&
&&&&&&&&& ps aux | sed -e 1d | sort -k3nr -k1,1 -k2n | head -n 20
&&&&&&&&& sleep 5
&& && done
&& && CTRL+D&& &
&& && /& ./test12.sh
&&& & 21:55:07 up 13:42,& 2 users,& load average: 0.00, 0.00, 0.00
&& && USER&&&&&& PID %CPU %MEM&&& VSZ&& RSS&& TTY&&&&& STAT START&& TIME&& COMMAND
&& && root&&&&& 6408&&&& 2.0&&&&& 0.0&& 4740&& 932&& pts/2&&& R+&&& 21:45&&&& 0:00&& ps aux
&& && root&&&&& 1755&&&& 0.2&&&&& 2.0& && ?&&&&&&& S&&&&& 08:14&&&& 2:08&& nautilus
&& && 68&&&&&&& 1195&&&& 0.0&&&&& 0.4&& 6940&& 4416&&& ?&&&&&&& Ss&&& 08:13&&&& 0:00&& hald
&& && postfix&& 1399&&& 0.0&&&&& 0.2& 1&&& ?&&&&&&& S&&&&& 08:13&&&& 0:00&& qmgr -l -t fifo -u
&& && postfix&& 6021&&& 0.0&&&&& 0.2& 1&&& ? &&&&&& S&&&&& 21:33&&&& 0:00&& pickup -l -t fifo -u
&& && root&&&&&&&& 1&&&&&& 0.0&&&&& 0.1&& 2828&& 1364&&& ?&&&&&&& Ss&&&& 08:12&&& 0:02 & /sbin/init
&& && ... ...
十三、格式化输出指定用户的当前运行进程:
&& && 在这个例子中,我们通过脚本参数的形式,将用户列表传递给该脚本,脚本在读取参数后,以树的形式将用户列表中用户的所属进程打印出来。
&& && /& cat & test13.sh
&& && #!/bin/sh
& & & #1. 循环读取脚本参数,构造egrep可以识别的用户列表变量(基于grep的扩展正则表达式)。
&& && #2. userlist变量尚未赋值,则直接使用第一个参数为它赋值。
& &&& #3. 如果已经赋值,且脚本参数中存在多个用户,这里需要在每个用户名之间加一个竖线,在egrep中,竖线是分割的元素之间是或的关系。
& & & #4. shift命令向左移动一个脚本的位置参数,这样可以使循环中始终操作第一个参数。
& &&& while [ $# -gt 0 ]
& && &&&& if [ -z &$userlist& ]; then
&& && &&&&&&& userlist=&$1&
&& && &&& else
&&& && &&&&&& userlist=&$userlist|$1&
&&&& && & fi
&&&&& && & shift
&& && done
&& && #5. 如果没有用户列表,则搜索所有用户的进程。
& & & #6. &^ *($userlist) &: 下面的调用方式,该正则的展开形式为&^ *(root|avahi|postfix|rpc|dbus) &。其含义为,以0个或多个空格开头,之后将是root、avahi、postfix、rpc或dbus之中的任何一个字符串,后面再跟随一个空格。
& & & if [ -z &$userlist& ]; then
&& && &&& userlist=&.&
& & & else
& && &&&& userlist=&^ *($userlist) &
& & & #7. ps命令输出所有进程的user和命令信息,将结果传递给sed命令,sed将删除ps的title部分。
&& && #8. egrep过滤所有进程记录中,包含指定用户列表的进程记录,再将过滤后的结果传递给sort命令。
&& && #9. sort命令中的-b选项将忽略前置空格,并以user,再以进程名排序,将结果传递个uniq命令。
&& && #10.uniq命令将合并重复记录,-c选项将会使每条记录前加重复的行数。
&& && #11.第二个sort将再做一次排序,先以user,再以重复计数由大到小,最后以进程名排序。将结果传给awk命令。
&& && #12.awk命令将数据进行格式化,并删除重复的user。
&& && ps -eo user,comm | sed -e 1d | egrep &$userlist& |
&&&& && & sort -b -k1,1 -k2,2 | uniq -c | sort -b -k2,2 -k1nr,1 -k3,3 |
&&&&& && &&&& awk ' { user = (lastuser == $2) ? & & : $2;
&&&&&& & && &&&&&&&&&&& lastuser = $2;
&&&&&&&&&& & && &&&&&&& printf(&%-15s\t%2d\t%s\n&,user,$1,$3)
&&&&&&&&&&&&& }'
&& && CTRL+D
&& && /& ./test13.sh root avahi postfix rpc dbus
&& && avahi&&&&&&&&&&&& 2&&&&& avahi-daemon
&& && dbus&&&&&&&&&&&& 1&&&&& dbus-daemon
&& && postfix&&&&&&&&& 1&&&&& pickup
&& & && & &&&&&&&&&&&&&&& 1&&&&& qmgr
&& && root&&& & &&&&&&& 5&&&&& mingetty
&& &&&&&&&&&&&& & && &&&& 3&&&&& udevd
&& &&&&&&&&&&&&&&&& & &&& 2&&&&& sort
&& &&&&&&&&&&&&&&&&&&&&&& 2&&&&& sshd
&& && ... ...
&& && rpc&& & &&&&&&&&& 1&&&&& rpcbind
十四、用脚本完成which命令的基本功能:
&&&&& 我们经常会在脚本中调用其他的应用程序,为了保证脚本具有更好的健壮性,以及错误提示的准确性,我们可能需要在执行前验证该命令是否存在,或者说是否可以被执行。这首先要确认该命令是否位于PATH变量包含的目录中,再有就是该文件是否为可执行文件。
&& && /& cat & test14.sh
&& && #!/bin/sh
& & & #1. 该函数用于判断参数1中的命令是否位于参数2所包含的目录列表中。需要说明的是,函数里面的$1和$2是指函数的参数,而不是脚本的参数,后面也是如此。
& & & #2. cmd=$1和path=$2,将参数赋给有意义的变量名,是一个很好的习惯。
& & & #3. 由于PATH环境变量中,目录之间的分隔符是冒号,因此这里需要临时将IFS设置为冒号,函数结束后再还原。
&& && #4. 在for循环中,逐个变量目录列表中的目录,以判断该命令是否存在,且为可执行程序。
& & & isInPath() {
&& && &&& cmd=$1&&&&&&& path=$2&&&&& result=1
&&&& && & oldIFS=$IFS&& IFS=&:&
&&& && && for dir in $path
&&& && && do
&&&&& && &&&& if [ -x $dir/$cmd ]; then
&&&&&&& && &&&&&& result=0
&&&&&&&& && & fi
&&&&&&&&& done
&&&&& & & IFS=oldifs
&&&&& & & return $result
& & & #5. 检查命令是否存在的主功能函数,先判断是否为绝对路径,即$var变量的第一个字符是否为/,如果是,再判断它是否有可执行权限。
& & & #6. 如果不是绝对路径,通过isInPath函数判断是否该命令在PATH环境变量指定的目录中。
& & & checkCommand() {
&&& && && var=$1
&&&& && & if [ ! -z &$var& ]; then
&&&&& && &&&& if [ &${var:0:1}& = &/& ]; then
&&&&&&&&&& && &&& if [ ! -x $var ]; then
&&&&&&&&&&&&&& && &&& return 1
&&&&&&&&&&&& && & fi
&&&&&&&&&& && elif ! isInPath $var $PATH ; then
&&&&&&&&&& && &&& return 2
&&&&&&&&&& && fi
&&&&&&&&& fi
&& && #7. 脚本参数的合法性验证。
& & & if [ $# -ne 1 ]; then
& && &&&& echo &Usage: $0 command& &&2;
&& && #8. 根据返回值打印不同的信息。我们可以在这里根据我们的需求完成不同的工作。
&& && checkCommand $1
& & & case $? in
&& && 0) echo &$1 found in PATH.& ;;
& & & 1) echo &$1 not found or not executable.& ;;
& & & 2) echo &$1 not found in PATH.& ;;
& & & esac
& & & exit 0
& & & CTRL+D
& & & /& ./test14.sh echo
&& && echo found in PATH.
&& && /& ./test14.sh MyTest
&& && MyTest not found in PATH.
&& && /& ./test14.sh /bin/MyTest
& & & /bin/MyTest not found or not executable.
十五、验证输入信息是否合法:
& & & 这里给出的例子是验证用户输入的信息是否都是数字和字母。需要说明的是,之所以将其收集到该系列中,主要是因为它实现的方式比较巧妙。
&& && /& cat & test15.sh
&& && #!/bin/sh
&& && echo -n &Enter your input: &
&& && read input
&& && #1. 事实上,这里的巧妙之处就是先用sed替换了非法部分,之后再将替换后的结果与原字符串比较。这种写法也比较容易扩展。&& &
&& && parsed_input=`echo $input | sed 's/[^[:alnum:]]//g'`
&& && if [ &$parsed_input& != &$input& ]; then
&& & &&&& echo &Your input must consist of only letters and numbers.&
&& && else
&& &&&&&& echo &Input is OK.&
&& && CTRL+D
&& && /& ./test15.sh
&& && Enter your input: hello123
&& && Input is OK.
&& && /& ./test15.sh
&& && Enter your input: hello world
&& && Your input must consist of only letters and numbers.
十六、整数验证:
& & & 整数的重要特征就是只是包含数字0到9和负号(-)。
&& && /& cat & test16.sh
&& && #!/bin/sh
&& && #1. 判断变量number的第一个字符是否为负号(-),如果只是则删除该负号,并将删除后的结果赋值给left_number变量。
&& && #2. &${number#-}&的具体含义,可以参考该系列博客中&Linux Shell常用技巧(十一)&,搜索关键字&变量模式匹配运算符&即可。
&& && number=$1
&& && if [ &${number:0:1}& = &-& ]; then
&& & &&&& left_number=&${number#-}&
&& && else
&& &&&&&& left_number=$number
&& && #3. 将left_number变量中所有的数字都替换掉,因此如果返回的字符串变量为空,则表示left_number所包含的字符均为数字。
&& && nodigits=`echo $left_number | sed 's/[[:digit:]]//g'`
&& && if [ &$nodigits& != && ]; then
&& &&&&&& echo &Invalid number format!&
&& && else
&& &&&&&& echo &You are valid number.&
&& && CTRL+D
&& && /& ./test16.sh -123
&& && You are valid number.
&& && /& ./test16.sh 123e
&& && Invalid number format!
十七、判断指定的年份是否为闰年:
&& && 这里我们先列出闰年的规则:
&& && 1. 不能被4整除的年一定不是闰年;
&& && 2. 可以同时整除4和400的年一定是闰年;
&& && 3. 可以整除4和100,但是不能整除400的年,不是闰年;
&& && 4. 其他可以整除的年都是闰年。
&& && #!/bin/sh&&&
&& && year=$1
& & & if [ &$((year % 4))& -ne 0 ]; then
&&& && && echo &This is not a leap year.&
&&&&& & & exit 1
&& && elif [ &$((year % 400))& -eq 0 ]; then
&&&& && & echo &This is a leap year.&
&&&&&& && exit 0
&& && elif [ &$((year % 100))& -eq 0 ]; then
&&&&& & & echo &This is not a leap year.&
&&&&&&&&& exit 1
&& && else
&&&&& & & echo &This is a leap year.&
&&&&&&&&& exit 0
&& && CTRL+D
&& && /& ./test17.sh 1933
&& && This is not a leap year.
&& && /& ./test17.sh 1936
&& && This is a leap year.
&& &&& &&&&
十八、将单列显示转换为多列显示:
&&&&& 我们经常会在显示时将单行的输出,格式化为多行的输出,通常情况下,为了完成该操作,我们将加入更多的代码,将输出的结果存入数组或临时文件,之后再重新遍历它们,从而实现单行转多行的目的。在这里我们介绍一个使用xargs命令的技巧,可以用更简单、更高效的方式来完成该功能。&&&
& & & /& cat & test18.sh
& & & #!/bin/sh
&& && #1. passwd文件中,有可能在一行内出现一个或者多个空格字符,因此在直接使用cat命令的结果时,for循环会被空格字符切开,从而导致一行的文本被当做多次for循环的输入,这样我们不得不在sed命令中,将cat输出的每行文本进行全局替换,将空格字符替换为%20。事实上,我们当然可以将cat /etc/passwd的输出以管道的形式传递给cut命令,这里之所以这样写,主要是为了演示一旦出现类似的问题该如果巧妙的处理。
& & & #2. 这里将for循环的输出以管道的形式传递给sort命令,sort命令将基于user排序。
&& && #3. -xargs -n 2是这个技巧的重点,它将sort的输出进行合并,-n选项后面的数字参数将提示xargs命令将多少次输出合并为一次输出,并传递给其后面的命令。在本例中,xargs会将从sort得到的每两行数据合并为一行,中间用空格符分离,之后再将合并后的数据传递给后面的awk命令。事实上,对于awk而言,你也可以简单的认为xargs减少了对它(awk)的一半调用。
& & & #4. 如果打算在一行内显示3行或更多的行,可以将-n后面的数字修改为3或其它更高的数字。你还可以修改awk中的print命令,使用更为复杂打印输出命令,以得到更为可读的输出效果。
& & & for line in `cat /etc/passwd | sed 's/ /%20/g'`
&& && &&& user=`echo $line | cut -d: -f1`
&&&& && & echo $user
& & & done | \
&& && &&& sort -k1,1 | \
&& && &&& xargs -n 2 | \
&&&&& & & awk '{print $1, $2}'
&& && CTRL+D
&& && /& ./test18.sh
& & & abrt adm
&& && apache avahi
&& && avahi-autoipd bin
&& && daemon daihw
&& && dbus ftp
&& && games gdm
&& && gopher haldaemon
&& && halt lp
&& && mail nobody
&& && ntp operator
&& && postfix pulse
&& && root rtkit
&& && saslauth shutdown
&& && sshd sync
&& && tcpdump usbmuxd
&& && uucp vcsa
十九、将文件的输出格式化为指定的宽度:
&& && 在这个技巧中,不仅包含了如何获取和文件相关的详细信息,如行数,字符等,而且还可以让文件按照指定的宽度输出。这种应用在输出帮助信息、License相关信息时还是比较有用的。
&& && /& cat & test19.sh
&& && #!/bin/sh
&& && #1. 这里我们将缺省宽度设置为75,如果超过该宽度,将考虑折行显示,否则直接在一行中全部打印输出。这里只是为了演示方便,事实上,你完全可以将该值作为脚本或函数的参数传入,那样你将会得到更高的灵活性。&& &
& & & my_width=75
& & & #2. for循环的读取列表来自于脚本的参数。
& & & #3. 在获取lines和chars变量时,sed命令用于过滤掉多余的空格字符。
& & & #4. 在if的条件判断中${#line}用于获取line变量的字符长度,这是Shell内置的规则。
&& && #5. fmt -w 80命令会将echo输出的整行数据根据其命令选项指定的宽度(80个字符)进行折行显示,再将折行后的数据以多行的形式传递给sed命令。
&& && #6. sed在收到fmt命令的格式化输出后,将会在折行后的第一行头部添加两个空格,在其余行的头部添加一个加号和一个空格以表示差别。
&&&&& & & lines=`wc -l & $input | sed 's/ //g'`
&&&&&&&&& chars=`wc -c & $input | sed 's/ //g'`
&&&&&&&&& owner=`ls -l $input | awk '{print $3}'`
&&&&&&&&& echo &-------------------------------------------------------------------------------&
&&&&&&&&& echo &File $input ($lines lines, $chars characters, owned by $owner):&
&&&&&&&&& echo &-------------------------------------------------------------------------------&
&&&&&&&&& do
&&&&&&&&&&&&& if [ ${#line} -gt $my_width ]; then
&&&&&&&&&&&&& & & echo &$line& | fmt -w 80 | sed -e '1s/^/& /' -e '2,$s/^/+ /'
&&&&&&&&&&&&& else
&&&&&&&&&&&& && & echo && $line&
&&&&&&&&&&&&& fi
&&&&&& && done & $input
&&&&&&&&& echo &-------------------------------------------------------------------------------&
&& && done | more
&& && CTRL+D
&& && /& ./test19.sh testfile
&& && -------------------------------------------------------------------------------
&& && File testfile.dat (3 lines, 645 characters, owned by root):
&& && -------------------------------------------------------------------------------
&& & &&& The PostgreSQL Global Development Group today released updates for all
&& && + active branches of the PostgreSQL object-relational database system,
&& && + including versions 9.1.2, 9.0.6, 8.4.10, 8.3.17 and 8.2.23. Users of any of
&& && + the several affected features in this release, including binary replication,
&& && + should update their PostgreSQL installations as soon as possible.
&& & &&& This is also the last update for PostgreSQL 8.2, which is now End-Of-Life
&& && + (EOL). Users of version 8.2 should plan to upgrade their PostgreSQL
&& && + installations to 8.3 or later within the next couple of months. For more
&& && + information, see our Release Support Policy.
&& & & & This is just a test file.
&& && -------------------------------------------------------------------------------
二十、监控指定目录下磁盘使用空间过大的用户:
&& && 在将Linux用作文件服务器时,所有的注册用户都可以在自己的主目录下存放各种类型和大小的文件。有的时候,有些用户的占用空间可能会明显超过其他人,这时就需要管理员可以及时发现这一异常使用状况,并根据实际情况作出应对处理。
& & & /& cat & test20.sh
& & & #!/bin/sh
& & & #1. 该脚本仅用于演示一种处理技巧,其中很多阈值都是可以通过脚本参来初始化的,如limited_qutoa和dirs等变量。
& & & limited_quota=200
& & & dirs=&/home /usr /var&
&& && #2. 以冒号作为分隔符,截取passwd文件的第一和第三字段,然后将输出传递给awk命令。
&& && #3. awk中的$2表示的是uid,其中1-99是系统保留用户,&=100的uid才是我们自己创建的用户,awk通过print输出所有的用户名给for循环。
&& && #4. 注意echo命令的输出是由八个单词构成,同时由于-n选项,echo命令并不输出换行符。
&& && #5. 之所以使用find命令,也是为了考虑以点(DOT)开头的隐藏文件。这里的find将在指定目录列表内,搜索指定用户的,类型为普通文件的文件。并通过-ls选项输出找到文件的详细信息。其中输出的详细信息的第七列为文件大小列。
&& && #6. 通过awk命令累加find输出的第七列,最后再在自己的END块中将sum的值用MB计算并输出。该命令的输出将会与上面echo命令的输出合并作为for循环的输出传递给后面的awk命令。这里需要指出的是,该awk的输出就是后面awk命令的$9,因为echo仅仅输出的8个单词。
&& && #7. 从for循环管道获取数据的awk命令,由于awk命令执行的动作是用双引号括起的,所以表示域字段的变量的前缀$符号,需要用\进行转义。变量$limited_quota变量将会自动完成命令替换,从而构成该awk命令的最终动作参数。
&& && for name in `cut -d: -f1,3 /etc/passwd | awk -F: '$2 & 99 {print $1}'`
&& &&&&&& echo -n &User $name exceeds disk quota. Disk Usage is: &
&& &&&&&& find $dirs -user $name -type f -ls |\
&& &&&&&&&&&&&& awk '{ sum += $7 } END { print sum / () & MB& }'
&& && done | awk &\$9 & $limited_quota { print \$0 }&
&& && CTRL+D
&& && /& ./test20.sh&& &
二十一、编写一个更具可读性的df命令输出脚本:
&& && 这里我们将以awk脚本的方式来实现df -h的功能。
& & & /& cat & test21.sh
&& && #!/bin/sh
&& && #1. $$表示当前Shell进程的pid。&& &
&& && #2. trap信号捕捉是为了保证在Shell正常或异常退出时,仍然能够将该脚本创建的临时awk脚本文件删除。
&& && awk_script_file=&/tmp/scf_tmp.$$&
&& && trap &rm -f $awk_script_file& EXIT
&& && #3. 首先需要说明的是,'EOF'中的单引号非常重要,如果忽略他将无法通过编译,这是因为awk的命令动作必须要用单引号扩住。
&& && #4. awk脚本的show函数中,int(mb * 100) / 100这个技巧是为了保证输出时保留小数点后两位。
&& && cat && 'EOF' & $awk_script_file
&& && function show(size) {
&& & &&&& mb = size / 1024;
&& &&&&&& int_mb = (int(mb * 100)) / 100;
&& &&&&&& gb = mb / 1024;
&& &&&&&& int_gb = (int(gb * 100)) / 100;
&& &&&&&& if (substr(size,1,1) !~ &[0-9]& || substr(size,2,1) !~ &[0-9]&) {
&&&&&&&&&&&&&
&& &&&&&& } else if (mb & 1) {
&& &&&&&&&&&& return size &K&;
&& &&&&&& } else if (gb & 1) {
&& &&&&&&&&&& return int_mb &M&;
&& &&&&&& } else {
&& &&&&&&&&&& return int_gb &G&;
&& &&&&&& }
&& && #5. 在BEGIN块中打印重定义的输出头信息。
&& && BEGIN {
&& &&&&&&&& printf &%-20s %7s %7s %7s %8s %s\n&,&FileSystem&,&Size&,&Used&,&Avail&,&Use%&,&Mounted&
&& && #6. !/Filesystem/ 表示过滤掉包含Filesystem的行,即df输出的第一行。其余行中,有个域字段可以直接使用df的输出,有的需要通过show函数的计算,以得到更为可读的显示结果。
&& && !/Filesystem/ {
&& &&&&&& size = show($2);
&& &&&&&& used = show($3);
&& &&&&&& avail = show($4);
&& &&&&&& printf &%-20s %7s %7s %7s %8s %s\n&,$1,size,used,avail,$5,$6
&& && df -k | awk -f $awk_script_file
&&&&& CTRL+D
&& && /& ./test12.sh
&& && FileSystem&&&&&&&&&&&&& Size&&&&&& Used& & & Avail&&&& Use%&& Mounted
&& && /dev/sda2&&&&&&&&&&&&& 3.84G&&& 2.28G&&&& 1.36G&&&&& 63% & /
&& && tmpfs&&&&&&&&&&&&& && 503.57M&&&& 100K 503.47M&&&&&&& 1%&& /dev/shm
&& && /dev/sda1&&&&&&&&&&&& 48.41M& 35.27M& 10.63M&&&&& 77%&& /boot
&& && /dev/sda3&&&&&&&&&&&&& 14.8G 171.47M& 13.88G&&&&& & 2%&& /home
二十二、编写一个用于添加新用户的脚本:
&& && 之所以在这里选择这个脚本,没有更多的用意,只是感觉这里的有些技巧和常识还是需要了解的,如/etc/passwd、/etc/shadow、/etc/group的文件格式等。
&& && /& cat & test22.sh
& & & #!/bin/sh
& & & #1. 初始化和用户添加相关的变量。&& &
&& && passwd_file=&/etc/passwd&
& & & shadow_file=&/etc/shadow&
& & & group_file=&/etc/group&
& & & home_root_dir=&/home&
&& && #2. 只有root用户可以执行该脚本。&& &
& & & if [ &$(whoami)& != &root& ]; then
&& && &&& echo &Error: You must be roor to run this command.& &&2
&&& && && exit 1
&& && echo &Add new user account to $(hostname)&
& & & echo -n &login: &
&& && read login
&& && #3. 去唯一uid,即当前最大uid值加一。
& & & uid=`awk -F: '{ if (big & $3 && $3 & 5000) big = $3 } END {print big + 1}' $passwd_file`
& & & #4. 设定新用户的主目录变量
&& && home_dir=$home_root_dir/$login
&& && gid=$uid
&& && #5. 提示输入和创建新用户相关的信息,如用户全名和主Shell。
& & & echo -n &full name: &
& & & read fullname
& & & echo -n &shell: &
& & & read shell
& & & #6. 将输入的信息填充到passwd、group和shadow三个关键文件中。
& & & echo &Setting up account $login for $fullname...&
& & & echo ${login}:x:${uid}:${gid}:${fullname}:${home_dir}:$shell && $passwd_file
& & & echo ${login}:*:99:7::: && $shadow_file
& & & echo &${login}:x:${gid}:$login& && $group_file
& & & #7. 创建主目录,同时将新用户的profile模板拷贝到新用户的主目录内。
& & & #8. 设定该主目录的权限,再将其下所有文件的owner和group设置为新用户。
& & & #9. 为新用户设定密码。
& & & mkdir $home_dir
& & & cp -R /etc/skel/.[a-zA-Z]* $home_dir
& & & chmod 755 $home_dir
& & & find $home_dir -print | xargs chown ${login}:${login}
&& && passwd $login
&& && exit 0
&& && CTRL+D
& & & /& ./test22.sh
& & & Add new user account to bogon
& & & login: stephen
& & & full name: Stephen Liu
&& && shell: /bin/shell
&& && Setting up account stephen for Stephen Liu...
&& && Changing password for user stephen.
& & & New password:
& & & Retype new password:
& & & passwd: all authentication tokens updated successfully.
二十三、kill指定用户或指定终端的用户进程:
&& && 这是一台运行Oracle数据库的Linux服务器,现在我们需要对Oracle做一些特殊的优化工作,由于完成此项工作需要消耗更多的系统资源,因此我们不得不杀掉一些其他用户正在运行的进程,以便节省出更多的系统资源,让本次优化工作能够尽快完成。
&& && /& cat & test23.sh
& & & #!/bin/sh
& & & user=&&
&& && tty=&&
&& && #1. 通过读取脚本的命令行选项获取要kill的用户或终端。-t后面的参数表示终端,-u后面的参数表示用户。这两个选项不能同时使用。
&& && #2. case中的代码对脚本选项进行验证,一旦失败则退出脚本。
&& && while getopts u:t: do
&& && &&& case $opt in
&&&& && & u) if [ &$tty& != && ]; then
&& &&&&&&&&& & & echo &-u and -t can not be set at one time.&
&& &&&&&&&&&&&&& exit 1
&&&&&&&&& & & fi
&&&&&&&&&&&&& user=$OPTARG
&&&&&&&&&&&&& ;;
&&&&&& && t)& if [ &$user& != && ]; then
&& &&&&&& & &&&& echo &-u and -t can not be set at one time.&
&& &&&&&&&&&&&&& exit 1
&&&&&&&&&&&&& fi
&&&&&&&&&&&&& tty=$OPTARG
&&&&&&&&&&&&& ;;
&&&&&&&&& ?) echo &Usage: $0 [-u user|-t tty]& &&2
&&&&&&&&&&&&& exit 1
&&&&&& && esac
&& && done
&& && #3. 如果当前选择的是基于终端kill,就用$tty来过滤ps命令的输出,否则就用$user来过滤ps命令的输出。
&& && #4. awk命令将仅仅打印出pid字段,之后传递给sed命令,sed命令删除ps命令输出的头信息,仅保留后面的进程pids作为输出,并初始化pids数组。
&& && if [ ! -z &$tty& ]; then
&&&&& & & pids=$(ps cu -t $tty | awk &{print \$2}& | sed '1d')
&& && else
&&&&& & & pids=$(ps cu -U $user | awk &{print \$2}& | sed '1d')
&& && #5. 判断数组是否为空,空则表示没有符合要求的进程,直接退出脚本。
&& && if [ -z &$pids& ]; then
&&&&& & & echo &No processes matches.&
&&&&&& && exit 1
&& && #6. 遍历pids数组,逐个kill指定的进程。
&& && for pid in $ do
&&&&& & & echo &Killing process[pid = $pid]... ...&
&&&&&& && kill -9 $pid
&& && done
&& && exit 0
&& && CTRL+D
&& && /& ./test23.sh -t pts/1
&& && Killing process[pid = 11875]... ...
&& && Killing process[pid = 11894]... ...
&& && /& ./test23.sh -u stephen
&& && Killing process[pid = 11910]... ...
&& && Killing process[pid = 11923]... ...
二十四、判断用户输入(是/否)的便捷方法:
&& && 对于有些交互式程序,经常需要等待用户的输入,以便确定下一步的执行流程。通常而言,当用户输入&Y/y/Yes/yes&时表示确认当前的行为,而当输入&N/n/No/no&时则表示否定当前的行为。基于这种规则,我们可以实现一个便捷确认方式,即只判断输入的首字母,如果为Y或y,表示确认,如为N或n,则为否定。
& & & /& cat & test24.sh
& & & #!/bin/sh
& & & echo -n &Please type[y/n/yes/no]: &
& & & read input
& & & #1. 先转换小写到大写,再通过cut截取第一个字符。
& & & ret=`echo $input | tr '[a-z]' '[A-Z]' | cut -c1`
& & & if [ $ret = &Y& ]; then
&&&&&&&&& echo &Your input is Y.&
& & & elif [ $ret = &N& ]; then
&& &&&&&& echo &Your input is N.&
&& && else
&& &&&&&& echo &Your input is error.&
&& && CTRL+D
&& && /& ./test24.sh
&& && Please type[y/n/yes/no]: y
&& && Your input is Y.
&& && /& ./test24.sh
&& && Please type[y/n/yes/no]: n
&& && Your input is N.&&
二十五、通过FTP下载指定的文件:
&& && 相比于手工调用FTP命令下载文件,该脚本提供了更为方便的操作方式。
&& && /& cat & test25.sh
&& && #!/bin/sh
&& && #1. 测试脚本参数数量的有效性。&& &
&& && if [ $# -ne 2 ]; then
&&&&& &&& echo &Usage: $0 ftp://... username& &&2
&&&&&& && exit 1
&& && #2. 获取第一个参数的前六个字符,如果不是&ftp://&,则视为非法FTP URL格式。这里cut的-c选项表示按照字符的方式截取第一到第六个字符。
&& && header=`echo $1 | cut -c1-6`
&& && if [ &$header& != &ftp://& ]; then
&&&&& & & echo &$0: Invalid ftp URL.& &&2
&&&&&&&&& exit 1
&& && #3. 合法ftp URL的例子:/download/test.tar
&& && #4. 针对上面的URL示例,cut命令通过/字符作为分隔符,这样第三个域字段表示server()。
&& && #5. 在截取filename时,cut命令也是通过/字符作为分隔符,但是&-f4-&将获取从第四个字段开始的后面所有字段(download/test.tar)。
&& && #6. 通过basename命令获取filename的文件名部分。
&& && server=`echo $1 | cut -d/ -f3`
&& && filename=`echo $1 | cut -d/ -f4-`
&& && basefile=`basename $filename`
&& && ftpuser=$2
&& && #7. 这里需要调用stty -echo,以便后面的密码输入不会显示,在输入密码之后,需要再重新打开该选项,以保证后面的输入可以恢复显示。
&& && #8. echo &&,是模拟一次换换。
&& && echo -n &Password for $ftpuser: &
&& && stty -echo
&& && read password
&& && stty echo
&& && echo &&
&& && #9. 通过HERE文档,批量执行ftp命令。
&& && echo ${0}: Downloading $baseile from server $server.
&& && ftp -n && EOF
&& && open $server
&& && user $ftpuser $password
&& && get $filename $basefile
&& && quit
&& && #10.Shell内置变量$?表示上一个Shell进程的退出值,0表示成功执行,其余值均表示不同原因的失败。
&& && if [ $? -eq 0 ]; then
&&&& && & ls -l $basefile
&& && exit 0
&& && CTRL+D
&& && /& ./test25.sh& /download/test.tar stephen
&& && Password for stephen:
&& && ./test25.sh: Downloading from server .
&& && -rwxr-xr-x. 1 root root 678 Dec& 9 11:46 test.tar
二十六、文件锁定:
& & & 在工业应用中,有些来自于工业设备的文件将会被放到指定的目录下,由于这些文件需要再被重新格式化后才能被更高层的软件进行处理。而此时负责处理的脚本程序极有可能是多个实例同时运行,因此这些实例之间就需要一定的同步,以避免多个实例同时操作一个文件而造成的数据不匹配等问题的发生。文件锁定命令可以帮助我们实现这一同步逻辑。
&& && /& cat & test26.sh
&& && #!/bin/sh
&& && #1. 这里需要先确认flock命令是否存在。
&& && if [ -z $(which flock) ]; then
&&& && && echo &flock doesn't exist.&
&&& && && exit 1
&& && #2. flock中的-e选项表示对该文件加排它锁,-w选项表示如果此时文件正在被加锁,当前的flock命令将等待20秒,如果能锁住该文件,就继续执行,否则退出该命令。
& & & #3. 这里锁定的文件是/var/lock/lockfile1,-c选项表示,如果成功锁定,则指定其后用双引号括起的命令,如果是多个命令,可以用分号分隔。
& & & #4. 可以在两个终端同时启动该脚本,然后观察脚本的输出,以及lockfile1文件的内容。
& & & flock -e -w 20 /var/lock/lockfile1 -c &sleep 10;echo `date` | cat && /var/lock/lockfile1&
& & & if [ $? -ne 0 ]; then
&&&& && & echo &Fail.&
&& && &&& exit 1
& & & else
&& && &&& echo &Success.&
&&& && && exit 0
&& && CTRL+D
二十七、用小文件覆盖整个磁盘:
&& && 假设我们现在遇到这样一个问题,公司的关键资料copy到测试服务器上了,在直接将其删除后,仍然担心服务器供应商可以将其恢复,即便是通过fdisk进行重新格式化,也仍然存在被恢复的风险,鉴于此,我们需要编写一个脚本,创建很多小文件(5MB左右),之后不停在关键资料所在的磁盘中复制该文件,以使Linux的inode无法再被重新恢复,为了达到这里效果,我们需要先构造该文件,如:
&& && /& find . -name &*& & testfile
&& && /& ls -l testfile
&& && -rwxr-xr-x. 1 root root 5123678 Dec& 9 11:46 testfile
&& && /& cat & test27.sh
&& && #!/bin/sh
&& && #1. 初始化计数器变量,其中max的值是根据当前需要填充的磁盘空间和testfile的大小计算出来的。
&& && counter=0
&& && max=2000000
&& && remainder=0
&& && #2. 每次迭代counter变量都自增一,以保证每次生成不同的文件。当该值大于最大值时退出。
&& && #3. 对计数器变量counter按1000取模,这样可以在每生成1000个文件时打印一次输出,以便看到覆盖的进度,输出时间则便于预估还需要多少时间可以完成。
&& && #4. 创建单独的、用于存放这些覆盖文件的目录。
&& && #5. 生成临时文件,如果写入失败打印出提示信息。
&& && while true
&& & && & ((counter=counter+1))
&& & && & if [ #counter -ge $max ]; then
&& &&& && &&& break
&& &&& && fi
&& &&& && ((remainder=counter%1000))
&& &&& && if [ $remainder -eq 0 ]; then
&& &&& && &&& echo -e &counter = $counter\t date = & $(date)
&& &&& && fi
&& &&& && mkdir -p /home/temp2
&& &&& && cat & testfile & &/home/temp/myfiles.$counter&
&& &&& && if [[ $? -ne 0 ]]; then
&& &&& & && & echo &Failed to wrtie file.&
&& &&& && & & exit 1
&& &&& && fi
&& && done
&& && echo &Done&
&& && CTRL+D
&& && /& ./test27.sh
&& && counter = 1000&& &&& &Fri Dec& 9 17:25:04 CST 2011
&& && counter = 2000&& &&& &Fri Dec& 9 17:25:24 CST 2011
&& && counter = 3000&& &&& &Fri Dec& 9 17:25:54 CST 2011
&& && ... ...
&& && 与此同时,可以通过执行下面的命令监控磁盘空间的使用率。
&& && /& watch -n 2 'df -h'
&& && Every 2.0s: df -h&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&& Fri Dec& 9 17:31:56 2011
&& && Filesystem&&&&&&&&&&& Size&& Used Avail Use% Mounted on
&& && /dev/sda2&&&&&&&&&&&& 3.9G& 2.3G& 1.4G& 63% /
&& && tmpfs&&&&&&&&&&&&&&& & 504M& 100K& 504M&& 1% /dev/shm
&& && /dev/sda1&&&&&&&&&&&&& 49M&& 36M&& 11M& 77% /boot
&& && /dev/sda3&&&&&&&&&&&&& 15G& 172M&& 14G&& 2% /home
&& && 我们也可以在执行的过程中通过pidstat命令监控脚本进程的每秒读写块数。&& &
二十八、统计当前系统中不同运行状态的进程数量:
&& && 在Linux系统中,进程的运行状态主要分为四种:运行时、睡眠、停止和僵尸。下面的脚本将统计当前系统中,各种运行状态的进程数量。
& & & /& cat & test28.sh
& & & #!/bin/sh
& & & #1. 初始化计数器变量,分别对应于运行时、睡眠、停止和僵尸。
& & & running=0
& & & sleeping=0
& & & stopped=0
& & & zombie=0
&& && #2. 在/proc目录下,包含很多以数字作为目录名的子目录,其含义为,每个数字对应于一个当前正在运行进程的pid,该子目录下包含一些文件用于描述与该pid进程相关的信息。如1表示init进程的pid。那么其子目录下的stat文件将包含和该进程运行状态相关的信息。
& & & #3. cat /proc/1/stat,通过该方式可以查看init进程的运行状态,同时也可以了解该文件的格式,其中第三个字段为进程的运行状态字段。
&& && #4. 通过let表达式累加各个计数器。
& & & for pid in /proc/[1-9]*
&&& && && ((procs=procs+1))
&&& && && stat=`awk '{print $3}' $pid/stat`
&&&& && & case $stat in
&&&&&& && &&& R) ((running=runing+1));;
&&&&& && &&&& S) ((sleeping=sleeping+1));;
&&&&& && &&&& T) ((stopped=stopped+1));;
&&&&& && &&&& Z) ((zombie=zombie+1));
&&&& && & esac
&& && done
& & & echo -n &Process Count: &
& & & echo -e &Running = $running\tSleeping = $sleeping\tStopped = $stopped\tZombie = $zombie.&
&& && CTRL+D
&& && /& ./test28.sh
&& && Process Count: Running = 0&&&&& Sleeping = 136& Stopped = 0&&&& Zombie = 0.
二十九、浮点数验证:
&& & 浮点数数的重要特征就是只是包含数字0到9、负号(-)和点(.),其中负号只能出现在最前面,点(.)只能出现一次。
&& && /& cat & test29.sh
&& && #!/bin/sh
& & & #1. 之前的一个条目已经介绍了awk中match函数的功能,如果匹配返回匹配的位置值,否则返回0。
&& && #2. 对于Shell中的函数而言,返回0表示成功,其他值表示失败,该语义等同于Linux中的进程退出值。调用者可以通过内置变量$?获取返回值,或者作为条件表达式的一部分直接判断。
& & & validint() {
& && &&&& ret=`echo $1 | awk '{start = match($1,/^-?[0-9]+$/); if (start == 0) print &1&; else print &0&}'`
&&& && && return $ret
& & & validfloat() {
&&&& && & fvalue=&$1&
&&&&& & & #3. 判断当前参数中是否包含小数点儿。如果包含则需要将其拆分为整数部分和小数部分,分别进行判断。
&&&&& & & if [ ! -z& $(echo $fvalue | sed 's/[^.]//g') ]; then
&&&&& && &&&& decimalpart=`echo $fvalue | cut -d. -f1`
&&&&&&& && && fractionalpart=`echo $fvalue | cut -d. -f2`
&&&&&&&& && & #4. 如果整数部分不为空,但是不是合法的整型,则视为非法格式。
&&&&&&&& && & if [ ! -z $decimalpart ]; then
&&&&&&&&& && &&&& if ! validint &$decimalpart& ; then
&&&&&&&&&&& && &&&&&& echo &decimalpart is not valid integer.&
&&&&&&&&&&&& && &&&&& return 1
&&&&&&&&&&&& && & fi
&&&&&&&&& & & fi
&&&&&&&&& & & #5. 判断小数部分的第一个字符是否为-,如果是则非法。
&&&&&&&&& & & if [ &${fractionalpart:0:1}& = &-& ]; then
&&&&&&&&&&&& && & echo &Invalid floating-point number: '-' not allowed after decimal point.& &&2
&&&&&&&&&&&& && & return 1
&&&&&&&&&& && fi
&&&&&&&&&& && #6. 如果小数部分不为空,同时也不是合法的整型,则视为非法格式。
&&&&&&&&&& && if [ &$fractionalpart& != && ]; then
&&&&&&&&&& && &&& if ! validint &$fractionalpart& ; then
&&&&&&&&&&& && &&&&&& echo &fractionalpart is not valid integer.&
&&&&&&&&&&&& && &&&&& return 1
&&&&&&&&&&& && && fi
&&&&&&&&& & & fi
&&&&&&&& && & #7. 如果整数部分仅为-,或者为空,如果此时小数部分也是空,则为非法格式。
&&&&&&& && && if [ &$decimalpart& = &-& -o -z &$decimalpart& ]; then
&&&&&&&&& && &&&& if [ -z $fractionalpart ]; then
&&&&&&&&&& && &&&&&&& echo &Invalid floating-point format.& &&2
&&&&&&&&&&&& && &&&&& return 1
&&&&&&&&&&& && && fi
&&&&&&&& && & fi
&&&&& & & else
&&&&&& && & & #8. 如果当前参数仅为-,则视为非法格式。
&&&&&&&&& & & if [ &$fvalue& = &-& ]; then
&&&&&&&&& && &&&& echo &Invalid floating-point format.& &&2
&&&&&&&&& && &&&& return 1
&&&&&&&& && & fi
&&&&&&&&& & & #9. 由于参数中没有小数点,如果该值不是合法的整数,则为非法格式。
&&&&&&& && && if ! validint &$fvalue& ; then
&&&&&&& && &&&&&& echo &Invalid floating-point format.& &&2
&&&&&&& && &&&&&& return 1
&&&&&& && &&& fi
&&&&&& && fi
&&&&& & & return 0
& & & }&&&
& & & if validfloat $1 ; then
& && &&&& echo &$1 is a valid floating-point value.&
&& && exit 0
&& && CTRL+D
& & & /& ./test29.sh 47895&&& &&
&&&&& 47895 is a valid floating-point value.
&& && /& ./test29.sh 47895.33
&& && 47895.33 is a valid floating-point value.
&& && /& ./test29.sh 47895.3e
&& && fractionalpart is not valid integer.
&& && /& ./test29.sh 4789t.34
& & & decimalpart is not valid integer.&&&
三十、统计英文文章中每个单词出现的频率:
&& && 这个技巧的主要目的是显示如何更好的使用awk命令的脚本。
& & & /& cat & test30.sh
&& && #!/bin/sh
&& && #1. 通过当前脚本的pid,生成awk脚本的临时文件名。
&& && #2. 捕捉信号,在脚本退出时删除该临时文件,以免造成大量的垃圾临时文件。
&& && awk_script_file=&/tmp/scf_tmp.$$&
&& && trap &rm -f $awk_script_file& EXIT
&& && #3. while循环将以当前目录下的testfile作为输入并逐行读取,在读取到末尾时退出循环。
& & & #4. getline读取到每一行将作为awk的正常输入。在内层的for循环中,i要从1开始,因为$0表示整行。NF表示域字段的数量。
& & & #5. 使$i作为数组的键,如果$i的值匹配正则表达式&^[a-zA-Z]+$&,我们将其视为单词而不是标点。每次遇到单词时,其键值都会递增。
&& && #6. 最后通过awk脚本提供的特殊for循环,遍历数组的键值数据。
& & & cat && 'EOF' & $awk_script_file
&& && BEGIN {
&&&& && & while (getline & &./testfile& & 0) {
&&&& && &&&&& for (i = 1; i &= NF; ++i) {
&&&&&& && && &&&& if (match($i,&^[a-zA-Z]+$&) != 0)
&&&&&&&& && &&&& &&&& arr[$i]++
&&&&&&&&& & & }
&&&&&& && }
&&&&&&&&& for (word in arr) {
&&&&&&& && && printf &word = %s\t count = %s\n&,word,arr[word]
&&&&&&&&& }
&& && awk -f $awk_script_file
& & & CTRL+D
& & & /& cat testfile
&& && hello world liu liu , ,
&& && stephen liu , ?
& & & /& ./test30.sh
& & & word = hello&&&&& count = 1
&& && word = world&&&& count = 1
&& && word = stephen count = 1
&& && word = liu&&&&&&&& count = 3
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:88161次
排名:千里之外
原创:12篇
转载:41篇
(5)(3)(16)(3)(1)(5)(4)(4)(2)(2)(3)(2)(1)(2)}

我要回帖

更多关于 大于小于 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信