파일 A에는 다음과 같은 유전자 행이 있습니다.
A,B,C,D,E
P,Q,R
G,D,V,K
L,Q,X,I,U,G 등등.
한 번에 각 행을 취하면 다음과 같은 유형의 출력을 어떻게 얻을 수 있습니까?
첫 번째 행의 경우:
A,B,C
B,C,D
C,D,E
두 번째 행의 경우:
피,Q,R
세 번째 행의 경우:
G,D,V
D,V,K
본질적으로 제가 원하는 것은 각 행에서 유전자의 "삼중항"을 찾는 것입니다. 첫 번째 삼중항은 처음 세 개의 유전자를 갖게 됩니다. 두 번째 삼중항은 두 번째, 세 번째, 네 번째 유전자를 갖게 됩니다. 마지막 삼중항은 행의 마지막 유전자로 끝납니다.
이를 수동으로 달성하는 것은 엄청난 작업이 될 것입니다. 저는 아직 Linux, Perl 또는 Python 스크립트를 마스터하여 이를 위한 스크립트를 작성할 수 없으므로 이 커뮤니티의 도움을 주시면 감사하겠습니다!
답변1
사용 awk
:
function wprint() {
print w[1], w[2], w[3];
}
function wshift(e) {
w[1] = w[2]; w[2] = w[3]; w[3] = e;
}
BEGIN { FS = OFS = "," }
{
wshift($1);
wshift($2);
wshift($3);
wprint();
for (i = 4; i <= NF; ++i) {
wshift($i);
wprint();
}
}
그 다음에:
$ awk -f script data.in
A,B,C
B,C,D
C,D,E
P,Q,R
G,D,V
D,V,K
L,Q,X
Q,X,I
X,I,U
I,U,G
스크립트 awk
는 세 가지 요소로 구성된 이동 창인 w
. 각 입력 행에 대해 창의 세 요소를 세 개의 첫 번째 필드로 채우고 이를 쉼표로 구분된 목록(뒤에 줄 바꿈)으로 인쇄합니다. 그런 다음 줄의 나머지 필드를 반복하여 창으로 이동하고 각 요소에 대한 창을 인쇄합니다.
입력 데이터의 행에 2개 미만의 필드가 포함되어 있으면 다음과 같은 결과가 나타납니다.
A,,
또는
A,B,
출력에서.
모든 입력 줄에 최소한 세 개의 필드가 있다고 확신하는 경우(또는 그렇지 않은 줄을 무시하려는 경우) 스크립트를 awk
약간 줄일 수 있습니다.
function wprint() {
print w[1], w[2], w[3];
}
function wshift(e) {
w[1] = w[2]; w[2] = w[3]; w[3] = e;
}
BEGIN { FS = OFS = "," }
{
for (i = 1; i <= NF; ++i) {
wshift($i);
if (i >= 3) {
wprint();
}
}
}
가변 창 크기를 사용한 첫 번째 스크립트 변형의 일반화:
function wprint(i) {
for (i = 1; i < n; ++i) {
printf("%s%s", w[i], OFS);
}
print w[n]
}
function wshift(e,i) {
for (i = 1; i < n; ++i) {
w[i] = w[i + 1];
}
w[n] = e;
}
BEGIN { FS = OFS = "," }
{
for (i = 1; i <= n; ++i) {
wshift($i);
}
wprint();
for (i = n + 1; i <= NF; ++i) {
wshift($i);
wprint();
}
}
그것을 사용하여:
$ awk -v n=4 -f script data.in
A,B,C,D
B,C,D,E
P,Q,R,
G,D,V,K
L,Q,X,I
Q,X,I,U
X,I,U,G
답변2
와 함께 perl
:
perl -F, -le 'BEGIN { $, = "," } while(@F >= 3) { print @F[0..2]; shift @F }' file
와 함께 awk
:
awk -F, -v OFS=, 'NF>=3 { for(i=1; i<=NF-2; i++) print $i, $(i+1), $(i+2) }' file
답변3
Perl을 사용하면 다음과 같이 해결할 수 있습니다.
perl -lne '/(?:([^,]+)(?=((?:,[^,]+){2}))(?{ print $1,$2 }))*$/' yourfile
perl -F, -lne '$,=","; print shift @F, @F[0..1] while @F >= 3'
perl -F, -lne '$,=","; print splice @F, 0, 3, @F[1,2] while @F >= 3'
이는 아래와 같이 확장된 방식으로 작성할 수 있습니다.
perl -lne '
m/
(?: # set up a do-while loop
([^,]+) # first field which shall be deleted after printing
(?=((?:,[^,]+){2})) # lookahead and remember the next 2 fields
(?{ print $1,$2 }) # print the first field + next 2 fields
)* # loop back for more
$ # till we hit the end of line
/x;
' yourfile
그리고 sed를 사용하면 다양한 명령을 사용하여 이를 수행할 수 있습니다.
sed -e '
/,$/!s/$/,/ # add a dummy comma at the EOL
s/,/\n&/3;ta # while there still are 3 elements in the line jump to label "a"
d # else quit processing this line any further
:a # main action
P # print the leading portion, i.e., that which is left of the first newline in the pattern space
s/\n// # take away the marker
s/,/\n/;tb # get ready to delete the first field
:b
D # delete the first field, and apply the sed code all over from the beginning to what remains in the pattern space
' yourfile
Dc도 다음을 수행할 수 있습니다.
sed -e 's/[^,]*/[&]/g;y/,/ /' gene_data.in |
dc -e '
[q]sq # macro for quitting
[SM z0<a]sa # macro to store stack -> register "M"
[LMd SS zlk>b c]sb # macro to put register "M" -> register "S"
[LS zlk>c]sc # macro to put register "S" -> stack
[n44an dn44an rdn10anr z3!>d]sd # macro to print 1st three stack elements
[zsk lax lbx lcx ldx c]se # macro that initializes & calls all other macros
[?z3>q lex z0=?]s? # while loop to read in file line by line and run macro "e" on each line
l?x # main()
'
결과
A,B,C
B,C,D
C,D,E
D,E,F
E,F,G
P,Q,R
G,D,V
D,V,K
L,Q,X
Q,X,I
X,I,U
I,U,G