Sed 按相同顺序在两个行号之间提取

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

我有一个文件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 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
before
sed
会遇到在不知道将有多少行输入的情况下选择行的问题,因此,如果要使用
tac
,我认为没有办法绕过
sed | tac | sed
。@Kent
awk
将处理
END
块,即使在显式调用
exit()
之后,程序也会工作。但是,你是对的,我可以重构它并合并
NR==stop
END
块。(已编辑)我看到的是空格而不是制表符,这与问题中不同,但距离足够近/易于修改
tr
也将用制表符替换尾随的换行符,这可能是问题,也可能不是问题。这就是为什么我要放一个sed