在Bash中连接非连续行

时间:2011-08-04 15:15:05

标签: bash shell concatenation

为了连接连续的行,我发现这是由Kanaka和GhostDog74发布的:

while read line; do echo -n $line; [ "${i}" ] && echo && i= || i=1 ; done < File

效果很好,但我想修改它以连接当前行和超出它的第4行,如下所示:

line1
line2
line3
line4
line5
line6
line7

line1,line4
line2,line5
line3,line6
etc.  

非常感谢任何帮助。

6 个答案:

答案 0 :(得分:2)

printf "%s\n" line1 line2 line3 line4 line5 line6 line7 line8  | 
awk 'NR > 3 {print prev3 ", " $0} {prev3=prev2; prev2=prev1; prev1=$0} '

产生

line1, line4
line2, line5
line3, line6
line4, line7
line5, line8

答案 1 :(得分:1)

如果数据位于文件'<data file>'

tail -n +4 <data file> | paste -d ',' <data file> - | head -n -3
  • 'tail'命令删除'<data file>'的前3行
  • 'paste'命令将'<data file>'与结果'tail'连接在一起,使用分隔符','
  • 'head'命令会移除'paste''tail'中不使用任何内容的最后3行。

答案 2 :(得分:1)

此外,在纯粹的bash中不需要文件:

<command that output something> | (read l1; read l2; read l3; while read l4; do echo "$l1,$l4"; l1=$l2; l2=$l3; l3=$l4; done)

修改

纯bash中的可扩展解决方案(更改n的值以更改第N行以外的当前行的cat):

<command that output something> | (n=3; i=0; 
while [ $i -lt $n ]; do read line[$i]; i=$((i+1)); done;
while read line[$n]; do
  echo "${line[0]},${line[$n]}";
  i=0; while [ $i -lt $n ]; do line[$i]=${line[$((i+1))]}; i=$((i+1)); done;
done)

答案 3 :(得分:1)

开始编辑

比bellow更简单的解决方案,也可以很容易地修改到第N行behond,总是在sed中:

<command that output something> | sed -n -e '1h;2,3H;4,${H;g;s/\n.*\n/,/;p;g;s/^[^\n]*\n//;h}'

可以使用sed -n -f script运行的解释版本:

# Do not put a \n in front of the hold space for the 1st line.
1h
# For all lines except the 1st, append to the hold space.
2,$H
# From the 1st line than need to be append to another line, 4 in this case, ...
4,${
# Copy the hold space in the patter space, replace all what is between \n by ',', and print.
g
s/\n.*\n/,/
p
# Remove the 1st line from the hold space.
g
s/^[^\n]*\n//
h}

结束修改

此外,无需文件的sed解决方案:

<command that output something> | sed -n -e 'H;g;s/^\n\(.*\)\n\(.*\n.*\n\)\(.*\)$/\1,\3\n\2\3/;t next;b;:next;P;s/^[^\n]*//;h'

作为所有神秘的sed解决方案,它值得一个解释,我以评论的sed脚本文件的形式提供,可以与sed -n -f script一起运行:

# Append current line to the hold space and copy the hold space in the pattern space.
H
g
# Now, the hold and pattern space contain '\n<line1>\n<line2>...'.
# If we can match 4 lines in the pattern space, append 1st and 4th line at the beginning of the pattern space and remove the 1st line.
# If no substitution occurs, start next cycle, else print the concatenation, remove the concatenation from the pattern space, and copy the pattern space in the hold space for next cycle.
s/^\n\(.*\)\n\(.*\n.*\n\)\(.*\)$/\1,\3\n\2\3/
t next
b
:next
P
s/^[^\n]*//
h

答案 4 :(得分:1)

在bash中使用数组:

declare -a arr; arr=($(< line1to7))
for n in {0..3} ; do echo ${arr[n]}","${arr[$n+3]} ; done
line1,line4
line2,line5
line3,line6
line4,line7

答案 5 :(得分:0)

我可能会使用Perl,但你几乎肯定也可以使用Python。

use strict;
use warnings;
my(@lines);
while (<>)
{
    chomp;
    if (scalar @lines >= 4)
    {
        my $old = shift @lines;
        print "$old,$_\n";
    }
    push @lines, $_;
}

给定一个非标准命令,range生成第1行到第20行,以及xxx.pl中的Perl脚本,这会产生:

$ range -f 'line%d' 1 20 | perl xxx.pl
line1,line5
line2,line6
line3,line7
line4,line8
line5,line9
line6,line10
line7,line11
line8,line12
line9,line13
line10,line14
line11,line15
line12,line16
line13,line17
line14,line18
line15,line19
line16,line20
$

如果那不是你想要的,你需要更清楚地解释你想要的东西。