sed awk 第二版学习(三)—— 编写 sed 脚本

2024-09-05 09:36
文章标签 学习 编写 脚本 第二 awk sed

本文主要是介绍sed awk 第二版学习(三)—— 编写 sed 脚本,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、在脚本中应用命令

二、寻址上的全局透明

三、测试并保存输出

1. 用于测试 sed 的 shell 脚本 testsed

2. sed 永久性改动的 shell 脚本 runsed

四、sed 脚本的四种典型应用

1. 对同一文件的多重编辑

2. 改变一组文件

3. 提取文件内容

(1)提取宏定义脚本 getmac

(2)生成提纲的脚本 do.outline

4. 编辑工作转移

五、几个使用 sed 脚本的提示


        使用 sed 可以将类似于 vi 编辑器中手动的操作过程提取出来,并转换成一个非手动的过程,即通过执行一个脚本来实现。大多数不熟悉 sed 的人都觉得,编写执行一系列编辑动作的脚本,比手动做一些改动更冒险。这种担心的原因是自动化任务会发生一些不可逆的事情。学习 sed 的目标就是要理解它从而可以预测执行结果。

        这就要求采用可控制的方式来使用 sed。在编写脚本时,应遵循以下这些步骤:

  1. 在着手做之前要弄清楚想做什么。
  2. 明确地描述处理过程。
  3. 在提交最终的改变之前反复测试这个过程。

        检测脚本是否中工作的最好方式,是使用不同的输入样本进行测试并观察结果。sed 工作的三个基本原理为:

  • 脚本中的所有编辑命令都将依次应用于每个输入行。
  • 命令应用于所有的行(全局的),除非行寻址限制了受编辑命令影响的行。
  • 原始的输入文件未被改变,编辑命令修改原始行的备份并将修改后的备份发送到标准输出。

一、在脚本中应用命令

        一次一行的设计的一个优点是 sed 比交互式屏幕编辑程序更适合处理大文件。后者必须将整个文件(或大部分)读入内存,这可能产生内存溢出或处理大文件时速度非常慢。sed 首先将整个编辑脚本应用于第一个输入行,然后再读取第二个输入行并对其应用整个脚本。因为 sed 总是处理原始行的最新形式,所以生成的任何编辑工作都会改变后续命令的应用的行。sed 不会保留最初的行,这意味着与原始输入行匹配的模式可能不再与经过编辑操作之后的行匹配。

        sed 维护一种模式空间,即一个工作区或临时缓冲区,当应用编辑命令时将在那里存储单个输入行。当应用了所有的指令后,当前行被输出并且输入的下一行被读入模式空间。然后脚本中的所有命令应用于新读入的行。

        结果是,任何 sed 命令都可以为应用下一个命令改变模式空间的内容。模式空间的内容是动态的,而且并不总是匹配最初的输入行。看个例子,假设输入为 pig cow,希望的输出为 cow horse。下面的 sed 命令输出中包含两个 horse:

s/pig/cow/
s/cow/horse/

        第一个命令将“pig”换成“cow”,第二个命令在同一行上将“cow”换成“horse”时,它还改变了由“pig”换成的“cow”。这个错误只是脚本命令中的顺序问题,技巧在于反转命令的顺序:

s/cow/horse/
s/pig/cow/

        一些 sed 命令会改变整个脚本的流程,例如 N 命令将另一行读入模式空间但不删除当前行,所以可以用来测试跨越多行的模式。其它一些命令告诉 sed,在到达脚本底部之前退出或者转到带标记的命令。sed 还维护了称为保持空间(hold space)的令一个临时缓冲区。可以将模式空间的内容复制到保持空间并在以后检索它们。

二、寻址上的全局透明

        sed 是隐式全局的,即缺省将命令应用于每个输入行。行地址用于提供操作(或限制)的上下文环境。sed 命令可以指定零个、一个或两个地址。每个地址都是一个描述模式、行号或者行寻址符号的正则表达式。

  • 如果没有指定地址,那么命令将应用于每一行。
  • 如果只有一个地址,那么命令应用于与这个地址匹配的任意行。
  • 如果指定了由逗号分隔的两个地址,那么命令应用于匹配第一个地址的第一行和它后面的行,直到匹配第二个地址的行(包括此行)。
  • 如果地址后面跟有感叹号(!),那么命令就应用于不匹配该地址的所有的行。

        删除所有行:

d

        只删除第一行:

1d

        行号指由 sed 维护的内部行号,该计数器不会因为多个输入文件而重置。因此不管指定多少个输入文件,在输入流中也只有一行 1。同样输入流也只有一个最后的行,可以使用寻址符号 $ 指定。

        删除输入的最后一行:

$d

        当正则表达式作为地址提供时,命令只影响于这个模式匹配的行。正则表达式必须封闭在斜杠(/)中。

        删除空行:

/^$/d

        如果提供两个地址,那么就指定了命令执行的行范围。

        删除 .TS 开头的行,一直删到(包含).TE 开头的行:

/^\.TS/,/^\.TE/d

        删除从行 50 到最后一行的所有行:

50,$d

        可以混合使用行地址和模式地址。

        删除从第一行直到第一个空行的所有行:

1,/^$/d

        可以把第一个地址看做是启动动作,并把第二个地址看做是禁用动作。sed 没办法先行决定第二个地址是否会匹配。一旦匹配了第一个地址,这个动作就将应用于这些行,于是命令应用于所有随后的行直到第二个地址被匹配。上例中如果没有空行,那么将删除所有行。

        跟在地址后面的感叹号会反转匹配的意义。

        删除除了 .TS 到 .TE(实际上是提取 .TS 到 .TE) 开头的行:

/^\.TS/,/^\.TE/!d

        sed 使用大括号({})将一个地址嵌套在另一个地址中,或者在相同的地址上应用多个命令。如果想指定行的范围,然后在这个范围内指定另一个地址,则可以嵌套地址。

        删除 .TS 开头到(包含).TE 开头的行中的空行:

/^\.TS/,/^\.TE/{
/^$/d
}

        左大括号必须在行末,而且右大括号必须独占一行。要确保在大括号后没有空格。可以使用大括号将编辑命令括起来以对某个范围的行应用多个命令。

        不仅删除 .TS/.TE 块中的空行,还在块中执行两个替换:

/^\.TS/,/^\.TE/{
/^$/d
s/^\.ps 10/.ps 8/
s/^\.vs 12/.vs 10/
}

三、测试并保存输出

        缺省 sed 将所有行送往标准输出(一般是屏幕),包括被修改的行和没有被修改的行,可以用重定向将这些输出保存到一个新文件。不要将输出重定向到输入文件,否则会改写输入文件,甚至可能在 sed 处理这个文件之前发生,并破坏数据。

# 将 sed 输出重定向到新文件
$ sed -f sedscr testfile > newfile# 比较文件,验证结果
$ diff testfile newfile

1. 用于测试 sed 的 shell 脚本 testsed

$ cat testsed 
#!/bin/bashfor x
dosed -f sedscr $x > tmp.$xdiff $x tmp.$x
done

2. sed 永久性改动的 shell 脚本 runsed

$ cat runsed 
#! /bin/bashfor x
doecho "editing $x: \c"if test "$x" = sedscr; thenecho "not editing sedscript!"elif test -s $x; thensed -f sedscr $x > /tmp/$x$$if test -s /tmp/$x$$thenif cmp -s $x /tmp/$x$$thenecho "file not changed: \c"elsemv $x $x.bak # save original, just in casecp /tmp/$x$$ $xfiecho "done"elseecho "Sed produced an empty file\c"echo " - check your sedscript."firm -f /tmp/$x$$elseecho "original file is empty."fi
done
echo "all done"

四、sed 脚本的四种典型应用

1. 对同一文件的多重编辑

        推荐逐步编写的技术,因为将每个命令隔离开可以容易看出哪些功能实现了,哪些还没有。如果同时尝试几个命令,则在问题出现时需要按和创建命令相反的过程来结束,即一个一个地删除命令直到找到问题为止。来看下面的例子。

        需求:

  1. 用 .LP 取代所有空行。
  2. 删除每行所有的前导空格。
  3. 删除打印机下划线的行,即以“+”开始的行。
  4. 删除添加在两个单词之间的多个空格。

        用部分文本逐个测试 sed 命令脚本:

$ cat sedscr
s/^ *$/.LP/
/^+ */d
s/^ *//
s/ */ /g
s/\. */. /g$ sed -f sedscr horsefeathers

        下一阶段使用 testsed 在完整的文件上测试脚本并彻底地检查结果,当对这个结果满意时,可以使用 runsed 生成永久性的改变:

$ runsed hf.product.bulletin
all done

2. 改变一组文件

        sed 最常见的用法是对一组文件进行一系列搜索和替换的编辑操作。这样的脚本不需要有趣,只要它们有用并能节省手工工作就行。通常这些脚本只是将单词或短语变成另一种形式的替换命令列表,例如:

s/ON switch/START switch/g
s/ON button/START switch/g
s/STANDBY switch/STOP switch/g
s/STANDBY button/STOP switch/g
s/STANDBY/STOP/g
s/[cC]abinet [Ll]ight/control panel light/g
s/core system diskettes/core system tape/g
s/TERM=542[05] /TERM=PT200 /g
s/Teletype 542[05]/BigOne PT200/g
s/542[05] terminal/PT200 terminal/g
s/Documentation Road Map/Documentation Directory/g
s/Owner\/Operator Guide/Installation and Operation Guide/g
s/AT&T 3B20 [cC]omputer/BigOne XL Computer/g
s/AT&T 3B2 [cC]omputer/BigOne XL Computer/g
s/3B2 [cC]omputer/BigOne XL Computer/g
s/3B2/BigOne XL Computer/g

        一旦这个脚本通过测试,就可以使用 runsed 一次性处理多个文件。文本之间有很大的不同,不能认为一种特殊情况为真,所有情况就都为真。测试每个文件是不切实际的,因此选择有代表性且包含异常的测试文件非常重要。使用 grep 检查大量输入很有帮助。

        在某些方面,编写脚本就像为给定事实的某种集合设计一个假设。通过增加测试数据来试着验证假设的合法性。如果打算在多个文件上运行该脚本,使用 testsed 首先在较小的示例上测试它,然后在许多文件上运行这个脚本。接着比较临时文件和原始文件来确认假设是否正确,有问题时修改脚本。花费在测试上的时间越多,那么在解决由拙劣脚本导致的问题上花费的时间就越少。

3. 提取文件内容

        sed 应用程序的一种典型的用法是从文件中提取相关的材料,这一功能类似于 grep,而且它具有在输出之前修改输入的又一优点。

(1)提取宏定义脚本 getmac

        脚本内容:

#! /bin/bash
# getmac -- print mm macro definition for $1
sed -n "/^\.de$1/,/^\.\.$/p" /usr/lib/macros/mmt

        执行方式:

$ getmac BL
.deBL
.if\\n(.$<1 .)L \\n(Pin 0 1n 0 \\*(BU
.if\\n(.$=1 .LB 0\\$1 0 1 0 \\*(BU
.if\\n(.$>1 \{.ie !\w^G\\$1^G .)L \\n(Pin 0 1n 0 \\*(BU 0 1
.el.LB 0\\$1 0 1 0 \\*(BU 0 1 \}
..

        下面的 getmac 版本允许用户将宏包的名字指定为第二个命令行参数。

#! /bin/bash
# getmac - read macro definition for $1 from package $2
file=/usr/lib/macros/mmt
mac="$1"
case $2 in
-ms) file="/work/macros/current/tmac.s";;
-mm) file="/usr/lib/macros/mmt";;
-man) file="/usr/lib/macros/an";;
esac
sed -n "/^\.de *$mac/,/^\.\.$/p" $file

(2)生成提纲的脚本 do.outline

        脚本内容:

sed -n '
s/"//g
s/^\.Se /CHAPTER /p
s/^\.Ah / A. /p
s/^\.Bh / B. /p' $*

        执行方式:

$ do.outline ch13/sect1
CHAPTER 13 Let the Computer Do the Dirty WorkA. Shell ProgrammingB. Stored CommandsB. Passing Arguments to Shell ScriptsB. Conditional ExecutionB. Discarding Used ArgumentsB. Repetitive ExecutionB. Setting Default ValuesB. What We've Accomplished

        do.outline 对在命令行上指定的所有文件($*)起作用。可以修改这个脚本以搜索任意种类的编码格式。例如:

sed -n '
s/[{}]//g
s/\\section/ A. /p
s/\\subsection/ B. /p' $*

4. 编辑工作转移

        在管道中进行编辑操作是 sed 作为真正的流编辑器的一个应用,这些编辑操作不会被写回到文件中。下面的例子是用脚本 format 将输入转换为 troff 能够处理的文本,具体是用 sed 处理输入,将一对连字符(--)替换为 troff 的 “\(em”。

        脚本 format 内容如下:

#! /bin/bash
eqn= pic= col=
files= options= roff="ditroff -Tps"
sed="| sed '/---/!s/--/\\(em/g'"
while [ $# -gt 0 ]
docase $1 in-E) eqn="| eqn";;-P) pic="| pic";;-N) roff="nroff" col="| col" sed= ;;-*) options="$options $1";;*) if [ -f $1 ]then files="$files $1"else echo "format: $1: file not found"; exit 1fi;;esacshift
done
eval "cat $files $sed | tbl $eqn $pic | $roff $options $col | lp"

        当对一个文档排版时,将连字符换成长破折号不是唯一要做的“美化”工作,因为有许多涉及到标点符号、空格和制表符等各种情况。脚本可能看上去如下所示:

s/^"/``/
s/"$/''/
s/"? /''? /g
s/"?$/''?/g
s/ "/ ``/g
s/" /'' /g
s/ "/ ``/g
s/" /'' /g
s/")/'')/g
s/"]/'']/g
s/("/(``/g
s/\["/\[``/g
s/";/'';/g
s/":/'':/g
s/,"/,''/g
s/",/'',/g
s/\."/.\\\&''/g
s/"\./''.\\\&/g
s/\\(em\\^"/\\(em``/g
s/"\\(em/''\\(em/g
s/\\(em"/\\(em``/g
s/@DQ@/"/g

五、几个使用 sed 脚本的提示

  1. 设计脚本前使用 grep 仔细检查输入文件,充分了解输入。
  2. 从测试文件中的小示例开始。在示例上运行脚本并且确信脚本能正常工作。记住,确保脚本在不想让它工作的地方不能工作同样重要。然后增加示例的规模,试着增加输入的复杂性。
  3. 仔细测试脚本中的每个命令,比较输入和输出文件看看发生了什么变化,亲自证明脚本是完整的。确认在输入文件正确的前提下,脚本可以正确地工作,而不仅仅是认为可以。
  4. 尝试用 sed 脚本完成工作,但不必100%。遇到困难时检查它们发生的频繁程度,有时手动来完成剩下的几个编辑工作比较好。

这篇关于sed awk 第二版学习(三)—— 编写 sed 脚本的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1138583

相关文章

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

闲置电脑也能活出第二春?鲁大师AiNAS让你动动手指就能轻松部署

对于大多数人而言,在这个“数据爆炸”的时代或多或少都遇到过存储告急的情况,这使得“存储焦虑”不再是个别现象,而将会是随着软件的不断臃肿而越来越普遍的情况。从不少手机厂商都开始将存储上限提升至1TB可以见得,我们似乎正处在互联网信息飞速增长的阶段,对于存储的需求也将会不断扩大。对于苹果用户而言,这一问题愈发严峻,毕竟512GB和1TB版本的iPhone可不是人人都消费得起的,因此成熟的外置存储方案开

【前端学习】AntV G6-08 深入图形与图形分组、自定义节点、节点动画(下)

【课程链接】 AntV G6:深入图形与图形分组、自定义节点、节点动画(下)_哔哩哔哩_bilibili 本章十吾老师讲解了一个复杂的自定义节点中,应该怎样去计算和绘制图形,如何给一个图形制作不间断的动画,以及在鼠标事件之后产生动画。(有点难,需要好好理解) <!DOCTYPE html><html><head><meta charset="UTF-8"><title>06

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

零基础学习Redis(10) -- zset类型命令使用

zset是有序集合,内部除了存储元素外,还会存储一个score,存储在zset中的元素会按照score的大小升序排列,不同元素的score可以重复,score相同的元素会按照元素的字典序排列。 1. zset常用命令 1.1 zadd  zadd key [NX | XX] [GT | LT]   [CH] [INCR] score member [score member ...]

【机器学习】高斯过程的基本概念和应用领域以及在python中的实例

引言 高斯过程(Gaussian Process,简称GP)是一种概率模型,用于描述一组随机变量的联合概率分布,其中任何一个有限维度的子集都具有高斯分布 文章目录 引言一、高斯过程1.1 基本定义1.1.1 随机过程1.1.2 高斯分布 1.2 高斯过程的特性1.2.1 联合高斯性1.2.2 均值函数1.2.3 协方差函数(或核函数) 1.3 核函数1.4 高斯过程回归(Gauss

【学习笔记】 陈强-机器学习-Python-Ch15 人工神经网络(1)sklearn

系列文章目录 监督学习:参数方法 【学习笔记】 陈强-机器学习-Python-Ch4 线性回归 【学习笔记】 陈强-机器学习-Python-Ch5 逻辑回归 【课后题练习】 陈强-机器学习-Python-Ch5 逻辑回归(SAheart.csv) 【学习笔记】 陈强-机器学习-Python-Ch6 多项逻辑回归 【学习笔记 及 课后题练习】 陈强-机器学习-Python-Ch7 判别分析 【学

系统架构师考试学习笔记第三篇——架构设计高级知识(20)通信系统架构设计理论与实践

本章知识考点:         第20课时主要学习通信系统架构设计的理论和工作中的实践。根据新版考试大纲,本课时知识点会涉及案例分析题(25分),而在历年考试中,案例题对该部分内容的考查并不多,虽在综合知识选择题目中经常考查,但分值也不高。本课时内容侧重于对知识点的记忆和理解,按照以往的出题规律,通信系统架构设计基础知识点多来源于教材内的基础网络设备、网络架构和教材外最新时事热点技术。本课时知识

线性代数|机器学习-P36在图中找聚类

文章目录 1. 常见图结构2. 谱聚类 感觉后面几节课的内容跨越太大,需要补充太多的知识点,教授讲得内容跨越较大,一般一节课的内容是书本上的一章节内容,所以看视频比较吃力,需要先预习课本内容后才能够很好的理解教授讲解的知识点。 1. 常见图结构 假设我们有如下图结构: Adjacency Matrix:行和列表示的是节点的位置,A[i,j]表示的第 i 个节点和第 j 个