sed
解决方案#2中给出了更全面的算术处理方法。此处介绍了使用sed
`sed' 自己的脚本。
由于过度“挥手”的不切实际的评论要求在解决方案#2中引起的大脑疼痛压力实际上是过多的代码“挥手”,并列,这是解决方案#3:
echo -e 'a\nb\nc\nd\ne' | sed -n '1!G;h;$p' | sed -n 3p
它仍然使用管道(“但也许有一种解决方法?”),其中数字 3 必须从文件 ala 的末尾“手动”替换为所需的行$-3
。
假设sed
脚本是 '$-4 p; $-6p; $-8 p;'
echo -e 'a\nb\nc\nd\ne\nf\ng\nh\ni' |
sed -n '1!G;h;$p' |
sed -n '4 p; 6p; 8 p;' |
sed -n '1!G;h;$p'
通过做这项工作
echo '$-4 p; $-6p; $-8 p;' | sed s/$-//
警告:
命令sed
必须像p
rint 一样简单。
“简单算术”只能是 '$-n' 的形式。
算术不是“正常”计算的。
一个“单个”“sed”命令字符串(如果之前的管道被视为这样,则为“行”)将嵌入并组合这两个命令,如下一个答案 #2 中所述。
致命一击。
鉴于这里第一个答案的敷衍解雇是#2:
由于这只是第二次或第三次编写大量sed
脚本,严重的语法微妙(s)规避破坏解决方案似乎就足够了:ala
# file prep
echo -e ' a\n b\n c\n d\n e\n f' >test
下面的删除线不是不正确的,但是在播放和“搞砸”sed
这里的 SO 问题之后,如果从模式缓冲区运行以通过以下方式获取文件长度行数,则sed
e
xecute 可以更简单,无需 IO 重定向$
:
sed -e '1{h; s/.*/sed -n "$=" test /e' -e 'p;x}; ${p;x;}' test
枚举从一$=
开始就保存在保持缓冲区中,并在最后再次打印。
# get "sed -n $= test" command output into sed script
sed -n '1esed -n "$=" test >sedr' test
# see where this is headed? so far "sed -n ... test" is irrelevant
# a pedantic "sed" only solution would keep it this way with
# all the required "sed"'ng as part of an 'e' command or '$e'
# where the 'sedr' file is itself "sed"'d ultimately to a final
# command 'sed -n /<the calculated line number>/p'
# one could quibble whether '>sedr' io redirection is "pure sed"
# modify 'sedr'with [the sed RPN][1] to get <the calculated line number>
# with judicious use of "sed"'s 'r' command and buffering will
# realize the effective script to compute the desired result
# this is left as an exercise needing perverse persistence with
# a certain amount of masochistic agony
作为如何进行的提示;使用解决方案#3 的技术,sed
脚本$-
地址现在被替换为$=
值 and -
。所以sed
又被用来编辑自己的脚本。
解析sed
脚本必须准确地只修改$-
in 地址。
此外,要使用 RPN 计算器,中缀算术必须具有后置固定运算符。在自动机和形式语言理论中,将波兰表示法或其反转转换为中缀是一种传统范式,反之亦然。
希望这可以确定可以做到的肯定答案(mais,pas par moi)和否定的答案,即它不是微不足道的练习(c'est par moi)。
任意解决方案的令人痛苦的理由在最后。
用于经验测试的环境:
linuxuser@ubuntu:~$ sed --version
sed (GNU sed) 4.4
Copyright (C) 2017 Free Software Foundation, Inc.
linuxuser@ubuntu:~$ uname -a
Linux ubuntu 4.15.0-74-generic #84-Ubuntu SMP Thu Dec 19 08:06:00 UTC 2019 i686 i686 i686 GNU/Linux
linuxuser@ubuntu:~$ lsbname -a
lsbname: command not found
linuxuser@ubuntu:~$ apropos lsb
lsb_release (1) - print distribution-specific information
lsblk (8) - list block devices
linuxuser@ubuntu:~$ lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04.2 LTS
Release: 18.04
Codename: bionic
解决方案#1
一种在盒子外面思考的技术:
seq 60 | sed -n '$!p' | sed -n '$!p' | sed -n '$!p' | sed -n '$p'
打印:
57
具体来说,对于倒数第二行:
sed -n '$!p' file | sed -n '$p'
更一般地说,脚本可以迭代sed -n '$!p'
以从文件末尾“倒数”。
好吧,答案是:
是否可以在 sed 地址中进行简单的算术运算?
从修辞上讲,它取决于一个人的能力、愿望和愿望以及对实用性的现实评估。同样,这意味着单个sed
调用应该专门用于此任务。但是,是的,这是可能的。
在自动机、形式语言和递归函数理论的研究中打下坚实的基础并没有什么坏处。
如前面的答案所述:不仅可以sed
做简单的算术,还可以做任何包括复杂算术的可计算函数。然而,要做到这一点需要实现sed
递归函数理论(RFT)的原始递归函数(PRF)(当然可以)。当然,机器架构的有限大小确实限制了没有无限磁带资源的计算,正如图灵机所证明的那样。在任何不希望证明这一点的情况下,可以在sed
手册中找到先例。
具体来说,做算术(有限)RPN计算器:
https ://www.gnu.org/software/sed/manual/html_node/Increment-a-number.html#FOOT9
现在,使用这样的工具可以创建一个sed
脚本,预先计算算术,然后嵌入到sed
脚本中以打印所需的输出。OP 给出了一个简单的演示,指出现在可以使用 RPNsed
脚本完成 shell 算术计算。
这简化为一种形式,例如(非常粗略)
sed '/$(sed RPN($= - 3*4) file)/;p;' file
但仍然需要提供sed
一个sed
'd 脚本。此外,可以说是对使用的bash $()
争论不休,但可以说它bash
已经被用来执行第一个“sed”,所以没有伤害就没有犯规。
认识到sed
实现 PRF 或等效地是图灵完备意味着是的,单次调用sed
就足够了。
因此,范式可以做到这一点。
可以加快此任务的一些命令是:
e, e command, r, R, w, W
除了通常的保持和模式缓冲区命令。
这些r, R, w, W
命令作为临时缓冲空间特别有利。
e [command] [3.7 Commands Specific to GNU sed][2]
This command allows one to pipe input from a shell command into
pattern space. Without parameters, the e command executes the
command that is found in pattern space ...
更抽象地说,尽管非常不切实际,但完全有可能编写一个sed
脚本来执行sed
范式本身,即使在地址中也包括算术计算。
一个sed
特点。表达式/\n/
不会匹配任何地址,并且仅当sed
像 'N'ext 或 s/.*/\n/ 这样的命令引入一个时,才会匹配模式空间中的地址。通过以下方式确认:
echo -e '\n\n' | sed -n ' /\n/ {s//hello/;p}'
但
echo -e '\n\n' | sed -n '0,/\n\n\n/ {s//hello/;p}'
输出3 个空行和
echo -e '\n\n' | sed -n '0,/\n/ {s/.*/hello/;p}'
echo -e '\n\n' | sed -n '0,/\n\n\n/ {s/.*/hello/;p}'
每个输出3 hello's
hello
hello
hello
虽然这是乖巧的:
echo -e '\n\n' | sed -n '0,/^$/ {s//hello/;p}'