공백으로 구분된 두 개의 열이 있는 파일이 있습니다. 두 번째 열에 T
는 or 중 하나만 있습니다 F
. 첫 번째 열의 문자를 읽고 싶습니다. 예를 들어 A
두 번째 열에 동일한 문자가 있는 3개의 행이 있으면 유지하지만 두 번째 열에 혼합 문자가 있는 경우 제거됩니다.T
A
B
D
A T
A T
A T
B T
B T
B F
C F
C F
D F
D T
D F
두 번째 필드에 동일한 첫 번째 필드의 모든 행에 값이 있으면 인쇄하고 싶습니다. 예상 출력:
A T
A T
A T
C F
C F
어쩌면 awk
그게 가능할까? 도움을 주셔서 미리 감사드립니다!
답변1
한 가지 방법은 다음과 같습니다 awk
.
awk 'NR==FNR{if (x[$1]++){if ($2!=t){z[$1]++}} else {t=$2};
next}!($1 in z)' infile infile
이 프로세스는 파일을 두 번 처리합니다. 첫 번째 패스에서는 첫 번째 필드가 동일한 값일 때 두 번째 필드의 값이 다른지 확인합니다. 그렇다면 $1
배열 인덱스로 사용되며, 두 번째 패스에서는 다음 경우에만 배치를 인쇄합니다. 첫 번째 필드는 해당 필드의 인덱스가 아닙니다. 또는 다음 과 함께
사용해도 괜찮다면 :sort
awk
sort -u infile | awk 'NR==FNR{seen[$1]++;next}seen[$1]==1' - infile
sort -u
파일에서 중복된 줄을 제거하고 결과를 파이프하여 awk
첫 번째 필드의 발생 횟수를 계산한 다음 전체 파일을 다시 처리하고 개수가 이면 줄을 인쇄합니다 1
.
답변2
sed -e '
# this is a do-while loop which collects lines till the time the first
# field remains the same. We break out of the loop when we see
# a line whose 1st field != prev lines 1st field **OR** we hit the eof.
:a
$bb
N
/^\(\S\+\) .\(\n\1 .\)*$/ba
:b
# all equal
# **Action:** Print and quit
/^\(\S\+ .\)\(\n\1\)*$/q
# all same 1st fld, but lines unequal, otw would have matched above
# **Action:** Drop the whole block as its uninteresting
/^\(\S\+\) .\(\n\1 .\)*$/d
# all equal, and trailing line part of next line
# **Action:** Display upto the last newline and restart
# with the trailing portion
/^\(\(\S\+ .\)\(\n\2\)*\)\n[^\n]*$/{
h
s//\1/p
g
}
# of same 1st fld but some lines unequal, and trailing portion has
# next line
# **Action:** strip till the last newline, and restart over with the
# trailing part
s/.*\(\n\)/\1/
D
' yourfile
이것은 "Sed"가 다루는 매우 흥미로운 문제입니다. 그러나 제가 찾은 것은 더 나은 것입니다. 아니면 OT가 SE에서 제공하는 더 큰 입력 세트라고 해야 할까요? 내 제안은 실제 크기와 종류의 테스트 사례를 http:/pastebin 사이트에 넣을 수 있다는 것입니다. 이는 이런 종류의 작업에 매우 유용할 것입니다.
답변3
접근 권한이 있는 경우GNU 데이터 혼합, 다음과 같이 데이터를 축소할 수 있습니다.
datamash -W groupby 1 countunique 2 collapse 2 < file
A 1 T,T,T
B 2 T,T,F
C 1 F,F
D 2 F,T,F
awk
이를 통해 다음 과 같은 후처리가 쉬워집니다 .
datamash -W groupby 1 countunique 2 collapse 2 < file |
awk '$2==1 {n = split($3,a,","); for (i=1;i<=n;i++) print $1, a[i]}'
A T
A T
A T
C F
C F
답변4
sed '
/\n/D
:1
$! {
N
/^\(\S\+\s\).*\n\1[^\n]\+$/ b1
}
/^\([^\n]\+\n\)\(\1\)\+[^\n]\+$/! D
h
s/\n[^\n]\+$//p
g
s/.*\n/\n/
D
' file