Làm cách nào để in tất cả các dòng của tệp có giá trị trùng lặp trong một cột nhất định


7

Đưa ra một tập tin như thế này:

1,768,12,46576457,7898
1,123,435,134,146
2,345,6756856,12312,1311
5,234,567465,12341,1341
1,3245,4356345,2442,13
9,423,2342,121,463
9,989,342,121,1212

Tôi muốn liệt kê tất cả các hàng (trong bash terminal) sao cho giá trị trong cột 1 xuất hiện ít nhất hai lần (trong cột 1). Kết quả phải là

1,768,12,46576457,7898
1,123,435,134,146
1,3245,4356345,2442,13
9,423,2342,121,463
9,989,342,121,1212

Câu trả lời:


11

Để thử và tránh lưu trữ toàn bộ tệp trong bộ nhớ, bạn có thể làm:

awk -F , '
  !count[$1]++ {save[$1] = $0; next}
  count[$1] == 2 {
    print save[$1]
    delete save[$1]
  }
  {print}'

4

Giải pháp Perl:

perl -F, -ane ' $h{ $F[0] } .= $_
                }{
                $h{$_} =~ tr/\n// >= 2 and print $h{$_} for keys %h
              ' < input-file
  • -n đọc dòng đầu vào theo dòng
  • -achia từng dòng trên -F, tức là dấu phẩy, thành @Fmảng.
  • các dòng được lưu trữ trong %hhàm băm được khóa bởi trường đầu tiên ( $F[0]). Chúng được nối với nhau ( .=).
  • ở cuối tập tin ("Lời chào Eskimo" }{), chúng tôi lặp lại các phím và đếm số dòng mới (sử dụng trtoán tử). Nếu ít nhất là 2, chúng tôi sẽ in các dòng được lưu trữ.

Bạn có thể cung cấp đầu ra cho | sort -nnếu bạn muốn cột đầu tiên được sắp xếp bằng số.

Chú ý: nếu dòng cuối cùng không kết thúc trong một dòng mới, nhóm của nó sẽ báo cáo kích thước của nó - 1. Bạn có thể tự chompmỗi dòng và thêm dòng mới để sửa nó hoặc sử dụng mảng các dòng thay vì mảng chuỗi.


1

Với awk (GNU awk cho mảng đa chiều)

gawk -F, '
    { line[NR] = $0; count[$1]++; found[$1][NR] = 1}
    END {
        for (id in count)
            if (count[id] > 1)
                for (nr in found[id]) 
                    print line[nr]
    }
' file

Thứ tự của đầu ra có thể không giống với tệp đầu vào.


Tôi tin rằng đó là GNU AWK 4. Các phiên bản trước xử lý các mảng đa chiều (giả) khác nhau.
Tạm dừng cho đến khi có thông báo mới.

1

Một awkcách tiếp cận khác để xóa các hàng duy nhất dựa trên cột số 1 (hoặc trả về các hàng trùng lặp dựa trên cột số 1)

awk -F, 'NR==FNR{s[$1]++;next} (s[$1]>1)' infile infile

0
for i in $(cat given | cut -d, -f1)
do
  linect=$(grep ^"${i}," given | wc -l)
  if [ ${linect} -gt 1 ]
  then
    grep ^"${i}," given >> result
  fi
done
sort result |uniq > desiredoutput

miễn là các trường được phân cách bằng dấu phẩy và bạn đang tìm kiếm các bản sao chỉ trong cột 1 và cột 1, điều này sẽ hoạt động.


có thể được viết làgrep -f <(cut -d, -f1 file | sort | uniq -c | awk '$1>1 {print "^"$2","}') file
glenn jackman

một trong nhiều cách nó có thể được viết, là trong ví dụ của tôi. Tôi chỉ muốn làm cho nó dễ hiểu hơn.
MelBurslan

2
hiểu. Chỉ làm cho nó hiệu quả hơn: một cuộc gọi grep so với cuộc gọi 2n.
glenn jackman

@glennjackman Tôi thích giải pháp của bạn. tuy nhiên, nó dường như không hoạt động với các tập tin lớn. Tôi không chắc đó có phải là vấn đề với grep không.
Bob

0

Một biến thể khác (nơi test.txtlà tệp đầu vào của bạn):

FILE=test.txt ; for n in $(cat ${FILE} | awk -F"," '{count[$1]++} END {for (i in count) print i":"count[i]}'|grep -v ':1'|awk -F: '{print $1}');do grep ^${n} ${FILE} ;done

Đó chỉ là về điều xấu nhất tôi từng thấy.
Tạm dừng cho đến khi có thông báo mới.

0

Sử dụng Python 3:

#!/usr/bin/env python3
import sys
from collections import defaultdict

column_delimiter = sys.argv[1]
column = int(sys.argv[2]) - 1

records = defaultdict(list)
for l in sys.stdin:
    l = l.rstrip('\n')
    r = l.split(column_delimiter)
    records[r[column]].append(l)

for ll in records.values():
    if len(ll) > 1:
        print(*ll, sep='\n')

Sử dụng:

python3 duplicate-columns.py COLUMN-DELIMITER COLUMN

Thí dụ:

python3 duplicate-columns.py ',' 1 < data.csv
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.