将多行中的相应字符粘贴在一起

Paste corresponding characters from multiple lines together

我正在编写一个 linux 命令,将多行中的相应字符拼接在一起。例如:我想更改这些行

A---
-B--
---C
--D-

对此:

A----B-----D--C-

到目前为止,我已经做到了:

cat sanger.a sanger.c sanger.g sanger.t | cut -c 1

这只对第一列有用,但它必须对所有列都有效。

有没有人可以帮忙?

编辑:这是一个更好的例子。我想要这个:

SUGAR

HONEY

CANDY

成为

SHC UOA GND AED RYY (without spaces)

更新规范的 Awk 方式

awk -vFS= '{for(i=1;i<=NF;i++)a[i]=a[i]$i}
           END{for(i=1;i<=NF;i++)printf "%s",a[i];print ""}' file

输出

A----B-----D--C-

SHCUOAGNNAEDRYY

P.s 对于大文件,这将占用大量内存

不使用 awk 的糟糕方法,你还需要事先知道字段数。

for i in {1..4};do cut -c $i test | tr -d "\n" ; done;echo

好吧,是时候来点疯狂的 sed 了! :D

免责声明:如果这是为了一些严肃的事情,请使用比这更不脆弱的东西。 想到 awk。除非您对自己的 sed 能力有足够的信心来保持这种疯狂。

cat file1 file2 etc | sed -n '1h; 1!H; $ { :loop; g; s/$/\n/; s/\([^\n]\)[^\n]*\n//g; p; g; s/^.//; s/\n./\n/g; h; /[^\n]/ b loop }' | tr -d '\n'; echo

这分为三个部分:假设您有一个文件 foo.txt

12345
67890
abcde
fghij

然后

cat foo.txt | sed -n '1h; 1!H; $ { :loop; g; s/$/\n/; s/\([^\n]\)[^\n]*\n//g; p; g; s/^.//; s/\n./\n/g; h; /[^\n]/ b loop }'

产生

16af
27bg
38ch
49di
50ej

之后,tr -d '\n'删除换行符,;echo在末尾添加一个。

这种疯狂的核心是 sed 代码,它是

1h
1!H
$ {
  :loop
  g
  s/$/\n/
  s/\([^\n]\)[^\n]*\n//g
  p
  g
  s/^.//
  s/\n./\n/g
  h
  /[^\n]/ b loop
}

这首先遵循基本模式

1h          # if this is the first line, put it in the hold buffer
1!H         # if it is not the first line, append it to the hold buffer
$ {         # if this is the last line, 
  do stuff  # do stuff. The whole input is in the hold buffer here.
}

在处理之前将所有输入组装到保持缓冲区中。一旦整个输入都在保持缓冲区中,就会发生这种情况:

  :loop
  g                         # copy the hold buffer to the pattern space
  s/$/\n/                   # put a newline at the end
  s/\([^\n]\)[^\n]*\n//g  # replace every line with only its first character
  p                         # print that
  g                         # get the hold buffer again
  s/^.//                    # remove the first character from the first line
  s/\n./\n/g                # remove the first character from all other lines
  h                         # put that back in the hold buffer
  /[^\n]/ b loop            # if there's something left other than newlines, loop

好了。我可能刚刚召唤克苏鲁

这是一个没有 awksed 的解决方案,假设文件名为 f:

paste -s -d "" <(for i in $(seq 1 $(wc -L < f)); do cut -c $i f; done)

wc -L 是一种 GNUism,它 returns 输入文件中最长行的长度,根据您的 version/locale 这可能不起作用。您可以通过执行以下操作来找到最长的行:

awk '{if (length > x) {x = length}} END {print x}' f

然后在seq命令中使用这个值代替上面的命令替换。