该进入第四章了,刚才看到一个帖子标题:我空有一身泡妞的好本领,但可惜自己是个妞。汗~这个。。。音乐无国界嘛,这个不应该也没性别界么?

第四章文本处理工具

书中先说明了以下排序的规则,数值的就不用说了,该大就大该小就小,但是字符型很多时候是区分声调或者重音的。在命令行中输入locale查看自己系统的编码配置。默认的是系统配置里的,但是可以自己设置排序的编码。如:

$ LC_ALL=C sort french-english #以传统ASCII码顺序排序

下边介绍以下排序命令sort:

语法: sort [ options ] [ file(s} ]

主要选项: -b 忽略开头的空白

-c 检查输入是否已正确地排序。如果未排序,则退出码为非零值,不会有任何输出

-d 字典顺序,仅文字数字和空白才有意义。

-g 一般数值:以浮点数字类型比较字段。仅GNU版本提供此选项功能

-f 将混用的字母都看作相同大小写,即忽略大小写。

-i 忽略无法打印的字符。

-k 定义排序键值字段

-m 将已排序的输入文件,合并为一个排序后的输出数据流

-n 以整数类型比较字段

-o outfile 将输出写到指定文件

-r 倒置排序由大到小,默认由小到大

-t char 使用单个字符char作为默认的字段分隔符取代空白字符

-u 只有唯一记录,丢弃所有具有相同键值的记录只留第一条。

另外排序键值字段类型标识,即-k一个字段之后的修饰符字母:

b 忽略开头的空白

d 字典顺序

f 不区分大小写

g 以一般的浮点数进行比较,只适用GNU版本

i 忽略无法打印的字符

n 以整数数字比较

r 倒置排序顺序

字段以及字段里的字符是由1开始编号的。如果仅指定一个字段编号,则排序键值会自该字段的起始处开始,一直继续到记录的结尾(而非字段结尾)。

如果给的是一对用逗号隔开的字段数字,则排序键值将由第一个字段值起开始,到第二个指定字段结尾结束。可能出现多个-k,会从第一个开始。

例子:

$ sort -t: -k1,1 /etc/passwd #以用户名称排序

$ sort -t: -k2nr /etc/passwd #反向UID的排序

$ sort -t: -k4n -k3n /etc/passwd $以GID与UID排序

关于sort的效率,搞算法的都比较了解目前各种排序算法的效率,这里的sort也没啥特别的,类似STL估计,组合排序算法尽可能的优化过了。不是搞算法的童鞋也不用了解了,相信它的效率就好了。

有时候我们还十分关心排序的稳定性,默认情况下是不稳定的,但是GNU实现了coreutils包弥补了不足,可以通过--stable选项来解决稳定性问题。(不懂稳定性的简单说一下:意思就是排序键值等同的时候需要以输入顺序来输出,即排序不打乱输入顺序)

有时候我们还需要解决输入数据的重复问题,sort -u能够解决一些,但是它消除的操作依据的是匹配的键值,而非匹配的记录。uniq命令提供另一种过滤数据的方式:它常用于管道中,用来删除已适用sort排序完成的重复记录。uniq有3个好用的选项:-c 可在每个输出行之前加上该行的重复次数。 -d选项则用于仅显示重复的行。 -u仅显示未重复的行。这里需要注意一点,uniq处理数据前是需要sort对数据进行排序的!

另外我们处理大量这样的数据的时候,我们需要重新格式化段落以方便我们使用或阅读。这时候可以使用fmt命令,有两个常用的选项:-s 仅切割较长的行,短行不会合并 ; -w n 则设置输出行宽度为n个字符(默认75个左右)。要考虑fmt移植性的请另行查询文档。

这里对可能使用到的统计行数、字数、字符数的wc命令做一个介绍,选项有-c 字节数 -l行数 -w 字数 。默认情况下给出行数 字数 字节数。

好了,处理了那么多文本,我们可能要打印出来看看,unix里支持的打印功能包括两类不同的命令,但拥有相同的功能,商用的unix系统与GNU/linux通常两种都支持,不过BSD系统仅支持Berkeley风格,POSIX则只定义了lp命令。

Berkeley System V 用途

lpr lp 传送文件到打印队列

lprm cancel 从打印队列中删除文件

lpq lpstat 报告队列状态

两套命令的例子:

$ lpr -Plcb102 sample.ps #将PostScript文件传送给打印队列lcb102

$ lpq -Plcb102 #查看打印队列状态

$ lprm -Plcb102 81352 #停止此进程!结束这个作业

然后是System V风格的:

$ lp -d lcb102 sample.ps #传送PostScript文件到打印队列lcb102

$ lpstat -t lcb102 #查看打印队列

$ cancel lcb102-81355 #结束这个作业

有时需打印数据需要加上页码或者时间戳,可以使用pr预处理要打印的数据。

语法:pr [ options ] [ file(s) ]

主要选项:

-cn 产生n栏的输出,可以简化成-n

-f 在首页之后的每一页标题前置一个ASCII分页字符标题,(有的环境下是-F)

-h althdr 将页标题内的文件名称,改用字符串althdr取代。

-ln 产生n行的页面

-on 输出位移n个空白

-t 不显示标题

-wn 每行至多n个字符。以单栏输出而言,如有需要会将较长的行切分绕回至另外一行;否则,在多栏输出的情况下,会截去长的行以符合指定。样例:

pr -f -l60 -o10 -w65 file(s) | lp 。

还有其他打印工具,这里说的比较简单,有这方面需求可以再搜些文档看看。

第五章管道的神奇魔力

在linux下的管理性文件,大部分都是文本文件,可以直接编辑阅读的,这些文件大部分放在标准目录:/etc下。我们写shell脚本的时候大部分时候都是在处理文本信息,而管道是可以一直顺序着连着使用的 如 .... | ... | ... 这样,书中举了个连着使用5个管道的处理passwd文件的例子说很厉害,大致就是这样。然后又写了一个脚本把文本转化成HTML文件。然后又弄了一个根据正则匹配的脚本来帮助玩文字解密游戏。再然后通过管道计算出了各种莎士比亚基本的单词出现频率等。管道的神奇就不罗嗦了。

第六章变量、判断、重复动作

有两个相似命令提供变量的管理,一个是readonly,可以将变量设置为只读模式,就是成为符号常量。export用于修改或者打印环境变量。他们都由一个-p选项,意思是打印命令的名称以及所有被导出(只读)变量的名称和值,这种方式可使得shell重新读取输出以便重新建立环境(只读设置)。

export -p可以显示所有当前的环境变量,如果要从程序的环境中删除变量,则要用env命令,也可以临时的改变环境变量值:

env -i PATH=$PATH HOME=$HOME LC_ALL=C .....

-i选项用来初始化(initializes)环境变量的,也就是丢弃任何的继承值,仅传递命令行上指定的变量给程序使用。

unset命令从执行中的shell中删除变量和函数,默认情况下,它会解除变量设置,也可以加上-v完成:

unset full_name #删除full_name变量

unset -v firest middle last #删除多个变量

unset -f full_function #删除函数

这里我尝试用unset删除readonly变量,发现无法删除。然后查询了以下,发现常量声明之后就无法更改包括删除,只有注销当前shell。

有时候输出某个变量时,希望连接别的字符,可以在变量名左右添加花括号如:

echo _${myvar}_ #这样会输出myvar变量并在前后增加下划线。

这样叫做参数的展开。如果变量未定义,展开后是null。

还有一种替换运算符:

${varname:-word} #如果varname存在且非null,则返回其值,否则返回word。

${varname:=word} #如果varname存在且非null,则返回其值,否则设置它为word然后再返回其值。

${varname:?message} #如果varname存在且非null,则返回它的值,否则显示varname:message,并退出当前的命令或脚本,如果省略message会出现默认信息parameter null or net set。

${varname:+word} #如果varname存在且非null,则返回word,否则返回null。

以上每个运算符内的冒号(:)都是可选的。如果省略冒号,则将每个定义中的“存在且非null”部分改为“存在”,也就是说,运算符仅用于测试变量是否存在。

还有模式匹配运算符#:

${variable#pattern} #如果模式匹配于变量值的开头处,则删除匹配的最短部分,并返回剩下的部分。

${variable##pattern} #如果模式匹配于变量值的开头处,则删除匹配的最长部分,并返回剩下的部分。

${variable%pattern} #如果模式匹配于变量的结尾处,则删除匹配的最短部分,并返回剩下的部分。

${variable%%pattern} #如果模式匹配于变量值的结尾处,则删除匹配的最长部分,并返回剩下的部分。

最后,POSIX标准化字符串长度运算符:${#variable}返回$variable值的字符长度。

学到这里我们就可以结合之前用到的位置参数来进行一些脚本程序的容错处理了,比如:filename=${1:-/dev/tty} #如果参数1为空则返回/dev/tty

之前我们没有介绍如何访问传递的参数的总数,这里说明一下,用的是 $# 符合。比如:

while [ $# !=0 ]

do

case $1 in

.... #处理第一个参数

esac

shift #移除第一个参数

done

另外还有$* ,$@ ,它们一次表示所有的命令行参数。这两个参数可用来把命令行参数传递给脚本或函数所执行的程序。

"$*" 表示将所有命令行参数视为单个字符串,等同于”$1 $2 ..."。$IFS的第一个字符用来作为分隔字符,以分隔不同的值来建立字符串。

“$@" 将所有命令行参数视为单独的个体,也就是单独字符串。等同于"$1" "$2" ...。这是将参数传递给其他程序的最佳方式,因为它会保留所有内嵌在每个参数里的任何空白。

shift命令是用来“截去(lops off)”来自列表的位置参数,由左开始。一旦执行shift,$1的初始值会永远消失,取而代之的是$2的旧值。$2的值变成$3的旧值,以此类推。$#值则会逐次减一。以上几个要多实验,不再赘述。

类似的还有很多特殊变量:(所有引用特殊变量前边加$符号)

# 目前进程的参数个数

@传递给当前进程的命令行参数。置于双引号内,会展开为个别的参数。

* 当前进程的命令行参数。置于双引号内,则展开为一单独参数。

- 在引用时给予shell的选项。

? 前一个命令的退出状态

$ shell进程的进程编号 process ID

0(零) shell程序的名称

! 最近一个后台命令的进程编号

ENV 一旦引用,则仅用于交互式shell中。$ENV的值是可展开的参数。

HOME 根目录

IFS 内部的字段分隔器,想想awk吧。

LANG 当前locale的默认名称;其他的LC_*变量会覆盖其值

LC_ALL 当前locale的名称,会覆盖LANG与其他LC_*变量

LC_COLLATE 用来排序字符的当前locale名称

LC_CTYPE 再模式匹配期间,用来确定字符类别的当前locale的名称

LC_MESSAGES 输出信息的当前语言的名称

LINENO 刚执行过的行再脚本或函数内的行编号

NLSPATH 再$LC_MESSAGES(XSI)所给定的信息语言里信息目录位置。

PATH 命令的查找路径

PPID 父进程的进程编号

PS1 主要的命令提示字符串,默认为“$”

PS2 行继续的提示字符串,默认为"> "

PS4 以set -x设置的执行跟踪的提示字符串。默认为“+ ”。

PWD 当前工作目录。

shell的算数运算符基本跟C语言一样,想直接在命令行测试算数运算符的需要这样加双括号:echo $(( 3&4 )) 之类的。

有一个要知道的地方,每一条命令,不管是内置的、shell函数,还是外部的,当它退出时,都会返回一个小的整数值给引用它的程序,这就是大家所熟悉的程序的退出状态(exit statu)。在shell下执行进程时,有许多方式可取用程序的退出状态。惯例来讲,退出状态为0表示成功执行完成,其他状态都是失败的。可以用ls命令执行对一次错一次分别看看返回状态是多少(上边有讲特殊变量 $? 可查看上一条命令的返回状态)。

POSIX的结束状态:

0 命令成功地退出

>0 在重定向或单词展开期间(~,变量,命令,算符展开,单词切割)失败。

1-125 命令不成功地退出,具体含义由各个单独的命令定义。

126 命令找到了,但文件无法执行。

127 命令找不到。

>128 命令因收到信号而死亡。

令人好奇的是,POSIX留下退出状态128未定义,仅要求它表示某种失败。因为只有低位的8个位会返回给父进程,所以大于255的退出状态都会替换成该值除以256之后的余数。返回值命令:exit value_number 。

关于判断语句 if-then-elif-else-fi 语句给个语法不再赘述:

if pipeline

[ pipeline ... ]

then

statements-if-true-1

[ elif pipeline

[ pipeline ... ]

then

statements-if-true-2 ... ]

[ else

statements-if-all-else-fails ]

fi

if判断力你可以使用 !、&&、|| 等C语言里的这些逻辑判断符号。

这里介绍一个test命令,它为了测试shell脚本里的条件,通过退出状态返回其结果,它有第二种形式即 [...] ,单要注意的是方括号根据字面意义逐字地输入,且必须与括号起来的expression以空白隔开。如:test "$str1" = "$str2" 等同于 [ "$str1" = "$str2" ] 。test有好多参数啊,好多。。。自己man吧(敢不敢把26个字母都用完?!!! TT)。这里给出之前的finduser脚本的改良版:

#! /bin/sh

#finduser --- 寻找是否有第一个参数指定的用户

if [ $# -ne 1 ]

then

echo Usage: finduser username >&2

exit 1

fi

who | grep $1

关于case语句,给出例子不再赘述,都十分雷同C语言的。

case $1 in #测试$1

-f )

.... #针对-f选项的程序代码

;; ##类似break

-d | --directory ) #支持长选项

...

* ) #上边都不匹配的默认选项,非必须

echo $1:unknow option >&2

exit 1

;; #也非必须

esac

关于for循环,给出一个实例:

for i in atlbrochure*.xml

do

echo $i

mv $i $i.old

sed 's/Athlanta/&, the capital of the South/' < $i.old >$i

done

这个循环将每个原始文件备份为副文件名为.old的文件,之后再使用sed处理文件建立新文件。同时有输出文件名,作为进度的一种提示。另外for循环里的in列表(list)是可选的,如果省略则遍历整个命令行参数,就好像输入了 for i in "$@" 。

while和until循环也都类似,语法为:

while condition

do

statements

done

until condition

do

statements

done

两者不同之处在于如何对待condition的退出状态,只要condition成功,while就继续循环。只要condition不成功,until则一直循环。

在以上循环里,你仍然可以使用break和continue,功能同C语言一样。

shift之前提到过,它还可以接受一个可选参数,也就是要移动几位。

针对参数的处理有一个getopts命令简化了选项处理,它能理解POSIX选项中将多个选项字母组织到一起的用法,也可以用来遍历整个命令行参数,一次一个参数。该命令会自动过滤掉参数里的-,--等符号。如果得到不合法选项字母,该命令会返回一个?符号。

shell脚本里的函数,一般可以定义在程序的最前部,也可以放在另一个独立文件里,并且以点号(.)命令来取用(source)它们。给出一个简单实例:

# wait_for_user user [ sleeptime ]

#

#语法:wait_for_user user [ sleeptime ]

wait_for_user () {

until who | grep "$1" > /dev/null

do

sleep ${2:-30}

done

}

调用直接 wait_for_user admin ,还可以接受第二个等待时间参数。在shell函数里,return与exit工作方式相同,可返回一个值,但是需要注意的是在shell函数里使用exit会终止整个shell命令。

linux shell脚本学习指南,shell脚本学习指南[二](Arnold Robbins Nelson H.F. Beebe著)相关推荐

  1. linux脚本是什么语言,Linux学习之Shell脚本语言的优势是什么?

    当我们学习Linux技术的时候,会涉及各种各样的知识和内容,比如说shell脚本语言,我想很多人都会疑惑shell脚本语言有什么优势?为何学习Linux的时候必须学习呢?我们来看看吧. 当命令和程序语 ...

  2. linux命令封装sh,shell脚本学习之调用脚本将文件打包zip的方法示例

    前言 本文主要给大家介绍的是关于调用脚本将文件打包zip的相关资料,分享出来供大家参考学习,下面来一起看看详细的介绍: 最近刚刚接触shell脚本,写了一点简单的练手.这里是用python调用脚本执行 ...

  3. (1)Shell 编程学习 Shell是什么?Shell的浅显原理 为什么要学Shell 及其第一个Shell脚本 CTF角度学习Shell

    最近刷CTF题目的时候经常要用到Shell语言,但是自己并没有系统的学习,所以最近花了点时间学习一下,所以重新来梳理一下.对于稍微有一点编程语言基础的同学,能上手Shell其实不需要半小时(甚至更短) ...

  4. (一)大数据学习之shell脚本

    一个菜鸡的学习.找工作的学习过程 自我学习使用 前言 一.熟悉常用的脚本语言(以shell作为学习展开) 1.1shell概述 1.2shell解析器 1.3shell脚本入门 1.4shell中的变 ...

  5. linux 脚本的作用,shell export 作用

    shell与export命令用户登录到Linux系统后,系统将启动一个用户shell.在这个shell中,可以使用shell命令或声明变量,也可以创建并运行 shell脚本程序.运行shell脚本程序 ...

  6. 【CyberSecurityLearning 34】Linux脚本编写(Shell脚本)

    目录 脚本 一个简单的脚本 实现流程: 变量赋值 IF判断语句 if单分支结构 if 双分支结构 if 多分支结构 实用案例:检测内网主机存活状态 Shell循环语句(for.while) for循环 ...

  7. linux脚本打印循环次数,shell脚本编程基础(3)——循环用法

    本节索引: 一.if.case条件判断 二.for.while及until循环 三.循环控制语句continue.break.shift及select菜单 四.信号捕捉trap 在前面的基础编程内容中 ...

  8. linux脚本编写规则,shell脚本编写守则

    现在centos7中使用的是bash软件,通过以下命令可以查看bash版本: [root@localhost ~]# cat /etc/redhat-release #查看系统的版本 CentOS L ...

  9. linux 函数自动补全,Shell脚本中实现自动补全功能

    对于Linuxer来说,自动补全是再熟悉不过的一个功能了.当你在命令行敲下部分的命令时,肯定会本能地按下Tab键补全完整的命令,当然除了命令补全之外,还有文件名补全. Bash-completion ...

最新文章

  1. TCP/IP 协议理解
  2. bitcoinj开发环境搭建
  3. string 替换_vim怎么查找与替换文字?比Windows记事本效率高太多了
  4. 如何跟程序员谈一场没有Bug的恋爱
  5. apache php并发数,apache查看当前并发数多少
  6. linux系统内核参数配置优化,Linux服务器内核参数优化
  7. Lintcode: O(1) Check Power of 2
  8. Oracle 1204 RAC failover 测试 (二)
  9. Linux Shell高级技巧(五)
  10. 特征筛选4——斯皮尔曼相关系数筛选特征(单变量筛选)
  11. Atlas读写分离Mysql集群的搭建
  12. SAP License:成本要素的拉入拉出
  13. python 函数参数枚举_Python中的枚举:如何在方法参数中强制执行
  14. PAT 1103 Integer Factorization[难]
  15. 软件安全测试之系统安全测试,软件安全测试报告模板.docx
  16. 软件测试肖sir___项目讲解之银行项目
  17. pojo和vo的含义
  18. Learn Git Branching学习笔记 Git常用命令
  19. 【问题解决】虚拟机打开gazebo黑屏、闪退、模型加载不出来
  20. Traffic Jams in the Land(线段树好题)

热门文章

  1. 华为手机设置页面黑色_华为手机望远镜功能在哪里设置
  2. 摩客怎么设置安卓的dp_摩客-官方版-摩客(Mockplus)V2.1.9.2-独木成林
  3. 计算机发论文攻略(收藏)
  4. 使用unity做的绩点计算器
  5. CA6140杠杆加工工艺及夹具设计831009(论文 CAD图纸 开题报告 任务书 工艺卡……)
  6. 安卓pdf阅读器_BOOX阅读器:不仅阅读效果逆天,PDF阅读和手写体验更出色!
  7. 【银行】2014年中信银行IT类笔试回忆版
  8. PhotoShop自学笔记
  9. mysql特殊字符波浪号_MySQL特殊字符
  10. usbview源码阅读与总结