解决方案#2 中给出了在sed 中进行算术的更全面的处理。使用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 命令必须像 print 一样简单。
“简单算术”只能是 '$-n' 的形式。
算术不是“正常”计算的。
“单个”“sed”命令字符串(如果将先前的管道视为此类,则为“行”)将嵌入并组合这两个命令,如下一个答案 #2 中所述。
致命一击。
鉴于这里第一个答案的敷衍解雇是#2:
由于这只是第二次或第三次编写大量 sed 脚本,严重的语法微妙(s)规避破坏解决方案似乎就足够了:ala
# file prep
echo -e ' a\n b\n c\n d\n e\n f' >test
下面的三振不是不正确的,但是在使用sedwith an SO problem over heresedexecute 玩并“搞砸”之后,如果从模式缓冲区运行以获取文件,则可以更简单地不进行 IO 重定向长度行数$ via:
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 脚本$- 地址现在被$= 值和- 替换。所以sed再次被用来编辑自己的脚本。
解析sed 脚本必须准确地修改仅地址中的$-。
此外,要使用 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 不仅可以进行简单的算术运算,还可以执行任何包含复杂算术运算的可计算函数。然而,这样做需要实现递归函数理论 (RFT) 的原始递归函数 (PRF)(当然 sed 会这样做)。当然,机器架构的有限大小确实限制了没有无限磁带资源的计算,正如图灵机所证明的那样。在任何不希望证明这一点的情况下,可以在sed 手册中找到先例。
具体来说,做算术(有限)一个 RPN 计算器:
https://www.gnu.org/software/sed/manual/html_node/Increment-a-number.html#FOOT9
现在,使用这样的工具可以创建一个sed 脚本,该脚本预先计算算术,然后嵌入到sed 脚本中以打印所需的输出。 OP 给出了一个简单的演示,指出现在可以使用 RPN sed 脚本完成 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
hello
hello
虽然这是表现良好:
echo -e '\n\n' | sed -n '0,/^$/ {s//hello/;p}'