awk / sed / shell合并/连接数据

时间:2010-04-30 23:05:01

标签: join sed awk

尝试合并我拥有的一些数据。输入看起来像这样:

foo bar
foo baz boo
abc def
abc ghi

我希望输出看起来像:

foo bar baz boo
abc def ghi

我有一些想法在shell脚本中使用一些数组,但我一直在寻找更优雅或更快的解决方案。

6 个答案:

答案 0 :(得分:3)

加入怎么样?

file="file"
join -a1 -a2 <(sort "$file" | sed -n 1~2p) <(sort "$file" | sed -n 2~2p)

那里的seds只是在奇数行和偶数行上分割文件

答案 1 :(得分:2)

虽然pixelbeat的答案有效,但我不能说我非常热衷于它。我想我会用awk这样的东西:

    { for (i=2; i<=NF; i++) { lines[$1] = lines[$1] " " $i;} }  
END { for (i in lines) printf("%s%s\n", i, lines[i]); }

这不应该要求对数据进行预排序,并且无论字段的数量或长度如何都应该正常工作(当然,没有内存溢出)。它唯一明显的缺点是它的输出是任意顺序的。如果你需要它排序,你需要通过排序管道输出(但回到原始顺序将是其他的东西)。

答案 2 :(得分:2)

awk解决方案

awk '
    {key=$1; $1=""; x[key] = x[key] $0}
    END {for (key in x) {print key x[key]}}
' filename

答案 3 :(得分:0)

如果第一个字段的长度是固定的,则可以将uniq-w选项一起使用。否则你晚上想要使用awk(警告:未经测试的代码):

awk '
    BEGIN{last='';}
    {
        if ($1==last) {
            for (i = 1; i < NF;i++) print $i;
        } else {
            print "\n", $0;
            last = $1;
        }
    }'

答案 4 :(得分:0)

Pure Bash,用于真正的交替线:

infile="paste.dat"

toggle=0
while read -a line ; do
  if [ $toggle -eq 0 ] ; then
    echo -n "${line[@]}"
  else
    unset line[0]               # remove first element
    echo  " ${line[@]}"
  fi
  ((toggle=1-toggle))
done < "$infile"

答案 5 :(得分:0)

基于fgm的纯Bash snippet

text='
foo bar
foo baz boo
abc def
abc ghi
'

count=0
oneline=""
firstword=""
while IFS=" " read -a line ; do
   let count++
   if [[ $count -eq 1 ]]; then
      firstword="${line[0]}"
      oneline="${line[@]}"
   else
      if [[ "$firstword" == "${line[0]}" ]]; then
         unset line[0] # remove first word of line
         oneline="${oneline} ${line[@]}"
      else
         printf "%s\n" "${oneline}"
         oneline="${line[@]}"
         firstword="${line[0]}"
      fi
  fi
done <<< "$text"
相关问题