Làm thế nào để tôi làm cho uniq chỉ xem xét lĩnh vực đầu tiên?


3

Tôi đang sử dụng FreeBSD 3.2-ĐÁNG TIN CẬY

Nếu tôi có một số văn bản được sắp xếp, như thế này last đầu ra

zikla13:Oct:20:22:34
zikla13:Oct:5:00:31
zikla14:Oct:17:22:01
zikla14:Oct:12:23:35
zikla14:Oct:12:23:34
zikla14:Oct:12:00:11
zikla14:Oct:11:23:52
zikla14:Oct:5:22:22
zilka13:Oct:13:23:48
zilka13:Oct:11:00:28
zilka13:Oct:9:22:40

Có một cách để có được uniq -c chỉ xem xét trường đầu tiên (có thể với -s )? Trong trường hợp này, đầu ra phải là:

2 zikla13:Oct:20:22:34
6 zikla14:Oct:17:22:01
3 zilka13:Oct:13:23:48

Hoặc một số cách khác sử dụng awk ?


Chào mừng bạn đến với Siêu người dùng! tôi có chỉnh sửa câu hỏi của bạn cho rõ ràng và liên quan đến thẻ. Xin lưu ý rằng trang web này (và những người khác thích nó ) tập trung vào việc hỏi và trả lời câu hỏi; những thứ như là lời cảm ơn của người Hồi giáo trong bài viết không được khuyến khích nâng cao chấp nhận câu trả lời hữu ích.
Blacklight Shining

Có nhiều cách thực hiện khác nhau uniq Đặc biệt, trong GNU uniq (được tìm thấy trên hầu hết các hệ thống dựa trên Linux) khác với uniq được tìm thấy trên BSD (bao gồm cả Mac OS X). Xin vui lòng chỉnh sửa câu hỏi của bạn để chỉ ra uniq thực hiện bạn đang hỏi về.
Blacklight Shining

Câu trả lời:


1

Với GNU uniq, hỗ trợ -w Tùy chọn:

$ cat data
zikla13:Oct:20:22:34
zikla13:Oct:5:00:31
zikla14:Oct:17:22:01
zikla14:Oct:12:23:35
zikla14:Oct:12:23:34
zikla14:Oct:12:00:11
zikla14:Oct:11:23:52
zikla14:Oct:5:22:22
zilka13:Oct:13:23:48
zilka13:Oct:11:00:28
zilka13:Oct:9:22:40
$ uniq -c -w7 data
  2 zikla13:Oct:20:22:34
  6 zikla14:Oct:17:22:01
  3 zilka13:Oct:13:23:48

Như đã chỉ ra trong các bình luận, giả sử trường đầu tiên luôn có bảy ký tự, đó là trong ví dụ của bạn, nhưng nếu nó không có trong đời thực, tôi không nghĩ có cách nào để làm điều đó với uniq (cộng với nếu bạn không Tôi không có GNU uniq, thậm chí -w sẽ không hoạt động), vì vậy đây là một giải pháp perl:

$ perl -ne '/(.*?):(.*)/;unless (exists $x{$1}){$x{$1}=[0,$2];push @x, $1};$x{$1}[0]++;END{printf("%8d %s:%s\n",$x{$_}[0],$_,$x{$_}[1]) foreach @x}' <data
   2 zikla13:Oct:20:22:34
   6 zikla14:Oct:17:22:01
   3 zilka13:Oct:13:23:48

Đây là cách nó hoạt động:

$ perl -ne

Chạy perl, không phải in từng dòng theo mặc định và sử dụng đối số tiếp theo làm tập lệnh.

/(.*?):(.*)/

Tách dòng đầu vào thành thứ trước dấu hai chấm đầu tiên và thứ sau dấu hai chấm đầu tiên, thành $1$2. split cũng sẽ làm việc ở đây

unless (exists $x{$1}){$x{$1}=[0,$2];push @x, $1}

Băm %x sẽ được sử dụng để xác định các dòng và mảng @x để giữ chúng theo thứ tự (bạn chỉ có thể sử dụng sort keys %x, nhưng điều đó giả định perl's sort sẽ sắp xếp theo cách tương tự như đầu vào được sắp xếp.) Vì vậy, nếu chúng ta chưa bao giờ thấy "khóa" hiện tại (nội dung trước dấu hai chấm đầu tiên), hãy khởi tạo một mục băm cho khóa và nhấn phím vào @x. Mục băm cho mỗi khóa là một mảng hai phần tử chứa số đếm và giá trị đầu tiên được nhìn thấy sau dấu hai chấm, do đó đầu ra có thể chứa giá trị đó.

$x{$1}[0]++

Tăng số lượng.

END{

Bắt đầu một khối sẽ được chạy sau khi tất cả các đầu vào đã được đọc.

printf("%8d %s:%s\n",$x{$_}[0],$_,$x{$_}[1])

In số đếm, được đệm bằng khoảng trắng, dấu cách, "phím", dấu hai chấm và nội dung từ sau dấu hai chấm.

foreach @x}

Làm điều đó cho mỗi khóa được nhìn thấy, theo thứ tự và kết thúc khối END.

<data

Đọc từ tệp được gọi là dữ liệu trong thư mục hiện tại để có được đầu vào. Bạn cũng có thể chuyển thành perl nếu bạn có một số lệnh hoặc đường ống khác tạo dữ liệu.


Điều này sẽ gây ra uniq chỉ xem xét bảy nhân vật. Nó sẽ hoạt động cho ví dụ của người hỏi, nhưng nó có thể sẽ bị hỏng nếu trường đầu tiên không dài chính xác bảy ký tự.
Blacklight Shining

@BlacklightShining Điểm tốt. Tôi sẽ thêm một giải pháp perl xử lý các ký tự thông qua: như trường để uniq, bất kể độ dài của chúng.
blm

uniq: tùy chọn bất hợp pháp - xin lỗi lỗi của tôi trong nhà điều hành -w FreeBSD 3.2-ĐÁNG TIN CẬY - không hỗ trợ -w
Da No

Vâng, khi bạn thêm bạn đang sử dụng FreeBSD, tôi đã hiểu -w sẽ không làm việc Tôi đã thêm một phiên bản perl mặc dù nó sẽ hoạt động ở bất cứ đâu và không dựa vào "khóa" là 7 ký tự.
blm

0

Tôi sẽ sử dụng awk. Lọc và đếm trường được phân tách bằng dấu hai chấm đầu tiên, khi nó thay đổi hoặc chúng ta nhấn EOF in toàn bộ dòng đã lưu trước đó và đếm:

awk -F: '!seen[$1]++ { line[$1]=$0; if(prev){printf "%d\t%s\n",seen[prev],line[prev]}; prev=$1} END {if(prev){printf "%d\t%s\n",seen[prev],line[prev]}}' data

Các awk kịch bản có thể được mở rộng ra như thế này:

# Count the occurrences of the first field. If first time then...
!seen[$1]++ {
    # save the line
    line[$1]=$0;
    # maybe print the previous line
    if (prev) {
        printf "%d\t%s\n", seen[prev], line[prev]
    };
    prev=$1
}

# End of file, so print any previous line we have got saved
END {
    if (prev) {
        printf "%d\t%s\n", seen[prev], line[prev]
    }
}

Nếu bạn có thể thay đổi dữ liệu được cung cấp cho awk bằng cách thêm một dòng trống ở cuối, bạn có thể phân phối với toàn bộ END {...} chặn, đơn giản hóa awk mã và loại bỏ trùng lặp:

( cat data; echo ) | awk ...

Xin lỗi nhưng đã thấy [: Không tìm thấy sự kiện. Đây là BSD thực sự cũ. Tôi sử dụng bash2.
Da No

@DaKhông bạn đã sử dụng dấu ngoặc đơn xung quanh awk biểu hiện như thể hiện trong một lớp lót?
roaima

có tôi sao chép tất cả các lệnh và dán vào thiết bị đầu cuối. . .
Da No
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.