Sed 按相同顺序在两个行号之间提取
我有一个文件1,其中有一列:Sed 按相同顺序在两个行号之间提取,sed,awk,Sed,Awk,我有一个文件1,其中有一列: File 1 apple pineapple banana cherry kiwi orange mango grape watermelon 我需要在两个行号之间以相同的顺序提取行的内容,用tab分隔。例如,对于第3行到第8行,输出应为: Output (Forward) banana cherry kiwi orange mango grape Output (reverse) mango orange kiwi cherry banana
File 1
apple
pineapple
banana
cherry
kiwi
orange
mango
grape
watermelon
我需要在两个行号之间以相同的顺序提取行的内容,用tab分隔。例如,对于第3行到第8行,输出应为:
Output (Forward)
banana cherry kiwi orange mango grape
Output (reverse)
mango orange kiwi cherry banana pineapple
对于第7行至第2行,输出应为:
Output (Forward)
banana cherry kiwi orange mango grape
Output (reverse)
mango orange kiwi cherry banana pineapple
我知道在行与行之间以正向顺序提取,但在反向顺序上有问题
sed '3,8!d'
我会用
sed '2,7!d' file1 | tac
tac
只需反向(逐行)重复给出的内容
对于制表符分隔的部分,有很多方法可以使用sed实现这一点。其中之一是
sed '2,7!d' | tac | sed '1h; 1!H; $!d; x; s/\n/\t/g'
这将在保持缓冲区中组合完整的输入,然后将其交换到模式空间,并用制表符替换其中的所有换行:
1h # first line: save to hold buffer
1!H # subsequent lines: append to hold buffer
$!d # if more input is to read, stop here (don't print anything)
x # otherwise: swap in assembled lines
s/\n/\t/g # replace newlines with tabs.
你也可以考虑使用<代码> Tr/代码>这个步骤,但是后面的换行符并不像人们最初想象的那么简单。
或者,您可以使用sed一次性完成全部工作:sed '2,7 { G; x; }; $!d; x; s/\n$//; s/\n/\t/g' file1
这有点棘手:
2,7 { # In lines 2 to 7:
G # Append the hold buffer to the pattern space
# this is originally a blank line and later the reverse
# of the lines already read
x # then swap it back into the hold buffer
}
$!d # If the input has not ended, stop here (print nothing)
x # When the whole input is consumed, swap the assembled
# reverse lines back in
s/\n$// # remove the trailing newline
s/\n/\t/g # then replace the newlines with tabs
哪种方法更好,这有点难以捉摸。后者对于sed仍然有一定的合理性,但更复杂的sed脚本的蝙蝠侠解码环特性已经显现出来。坦率地说,这样说对我很不好,因为我对SED有一个软肋,在这个实例中考虑放弃SED更长的但更可读的选择,比如<代码> AWK < /C> >:,这不是一个坏主意。
awk 'NR == 2, NR == 7 { result = $0 sep result; sep = "\t" } END { print result }' file1
我会用
sed '2,7!d' file1 | tac
tac
只需反向(逐行)重复给出的内容
对于制表符分隔的部分,有很多方法可以使用sed实现这一点。其中之一是
sed '2,7!d' | tac | sed '1h; 1!H; $!d; x; s/\n/\t/g'
这将在保持缓冲区中组合完整的输入,然后将其交换到模式空间,并用制表符替换其中的所有换行:
1h # first line: save to hold buffer
1!H # subsequent lines: append to hold buffer
$!d # if more input is to read, stop here (don't print anything)
x # otherwise: swap in assembled lines
s/\n/\t/g # replace newlines with tabs.
你也可以考虑使用<代码> Tr/代码>这个步骤,但是后面的换行符并不像人们最初想象的那么简单。
或者,您可以使用sed一次性完成全部工作:sed '2,7 { G; x; }; $!d; x; s/\n$//; s/\n/\t/g' file1
这有点棘手:
2,7 { # In lines 2 to 7:
G # Append the hold buffer to the pattern space
# this is originally a blank line and later the reverse
# of the lines already read
x # then swap it back into the hold buffer
}
$!d # If the input has not ended, stop here (print nothing)
x # When the whole input is consumed, swap the assembled
# reverse lines back in
s/\n$// # remove the trailing newline
s/\n/\t/g # then replace the newlines with tabs
哪种方法更好,这有点难以捉摸。后者对于sed仍然有一定的合理性,但更复杂的sed脚本的蝙蝠侠解码环特性已经显现出来。坦率地说,这样说对我很不好,因为我对SED有一个软肋,在这个实例中考虑放弃SED更长的但更可读的选择,比如<代码> AWK < /C> >:,这不是一个坏主意。
awk 'NR == 2, NR == 7 { result = $0 sep result; sep = "\t" } END { print result }' file1
按相反顺序处理行是一项任务
sed
不适合。由于它作为流处理器的性质,它被设计成按正向顺序处理行
我强烈建议使用awk
。基本上,即使是awk
也不提供按相反顺序处理输入文件的功能,但它提供了编程语言功能来缓冲感兴趣的行,并在到达停止行后按相反顺序打印它们:
script.awk:
或
您可以使用所需的任何其他编程语言来代替
awk
。按相反顺序处理行是一项任务sed
不适合。由于它作为流处理器的性质,它被设计成按正向顺序处理行
我强烈建议使用awk
。基本上,即使是awk
也不提供按相反顺序处理输入文件的功能,但它提供了编程语言功能来缓冲感兴趣的行,并在到达停止行后按相反顺序打印它们:
script.awk:
或
您可以使用您想要的任何其他编程语言,而不是awk
。我希望使用awk:
awk -v from="7" -v to="2" 'BEGIN{rev=from>to;s=rev?to:from;e=rev?from:to}
NR>=s && NR<=e{r[NR]=$0}
NR>e{
while(from!=to){
printf "%s\t",r[from]
rev?--from:++from
}
print r[from]
exit}' file
我想用awk:
awk -v from="7" -v to="2" 'BEGIN{rev=from>to;s=rev?to:from;e=rev?from:to}
NR>=s && NR<=e{r[NR]=$0}
NR>e{
while(from!=to){
printf "%s\t",r[from]
rev?--from:++from
}
print r[from]
exit}' file
$cat tst.awk
开始{
OFS=“\t”
如果(beg=min{a[NR]=0}
NR==最大值{
for(i=beg;i!=end;i+=delta){
printf“%s%s”,a[i],OFS
}
打印[结束]
出口
}
$awk-v beg=3-v end=8-f tst.awk文件
香蕉樱桃猕猴桃橙芒果葡萄
$awk-v beg=7-v end=2-f tst.awk文件
芒果橙猕猴桃樱桃香蕉菠萝
$cat tst.awk
开始{
OFS=“\t”
如果(beg=min{a[NR]=0}
NR==最大值{
for(i=beg;i!=end;i+=delta){
printf“%s%s”,a[i],OFS
}
打印[结束]
出口
}
$awk-v beg=3-v end=8-f tst.awk文件
香蕉樱桃猕猴桃橙芒果葡萄
$awk-v beg=7-v end=2-f tst.awk文件
芒果橙猕猴桃樱桃香蕉菠萝
我在第一次阅读问题时忽略了反向顺序要求tac
是一个很好的方法!在我第一次阅读这个问题时,我忽略了倒序的要求tac
是一个很好的方法!在代码< > NR=停止> /COD>时,最好考虑退出,但是我认为您应该将代码在<代码>结束{} /Cux>块中移动到<代码> NR==停止< /代码>。或者,除非用户指定的max(开始、停止)=lastLine
,否则不会有输出。实际上,END{…}
不是必需的。我认为你的sed|tac
行行不通。您在tac
获取该行之前正在组装该行,因此tac
只有一行要反转tac
beforesed
会遇到在不知道将有多少行输入的情况下选择行的问题,因此,如果要使用tac
,我认为没有办法绕过sed | tac | sed
。@Kentawk
将处理END
块,即使在显式调用exit()
之后,程序也会工作。但是,你是对的,我可以重构它并合并NR==stop
和END
块。(已编辑)我看到的是空格而不是制表符,这与问题中不同,但距离足够近/易于修改tr
也将用制表符替换尾随的换行符,这可能是问题,也可能不是问题。这就是为什么我要放一个sed