将多行中的相应字符粘贴在一起
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
好了。我可能刚刚召唤克苏鲁
这是一个没有 awk
或 sed
的解决方案,假设文件名为 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
命令中使用这个值代替上面的命令替换。
我正在编写一个 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
好了。我可能刚刚召唤克苏鲁
这是一个没有 awk
或 sed
的解决方案,假设文件名为 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
命令中使用这个值代替上面的命令替换。