2008-11-17 54 views
43

Tôi chắc chắn có một cách nhanh chóng và dễ dàng để tính tổng của một cột giá trị trên các hệ thống Unix (sử dụng một cái gì đó như awk hoặc xargs có lẽ), nhưng viết một kịch bản shell để phân tích các dòng hàng theo dòng điều hiện ra trong đầu.Lệnh ngắn nhất để tính tổng của một cột đầu ra trên Unix?

Ví dụ, cách đơn giản nhất để sửa đổi lệnh dưới đây để tính toán và hiển thị tổng số cho cột SEGSZ (70300) là gì?

ipcs -mb | head -6 
IPC status from /dev/kmem as of Mon Nov 17 08:58:17 2008 
T   ID  KEY  MODE  OWNER  GROUP  SEGSZ 
Shared Memory: 
m   0 0x411c322e --rw-rw-rw-  root  root  348 
m   1 0x4e0c0002 --rw-rw-rw-  root  root  61760 
m   2 0x412013f5 --rw-rw-rw-  root  root  8192 

Trả lời

77
ipcs -mb | tail +4 | awk '{ sum += $7 } END { print sum }' 

Hoặc không đuôi:

ipcs -mb | awk 'NR > 3 { sum += $7 } END { print sum }' 

Sử dụng awk với bc để có kết quả dài tùy ý (tín dụng cho Jouni K.):

ipcs -mb | awk 'NR > 3 { print $7 }' | paste -sd+ | bc 
+0

+1 .. đã xóa bản sao của tôi :-) – toolkit

+0

Cảm ơn, rất hữu ích! Chạy lệnh đó, tôi nhận kết quả này: 6.59246e + 08. Bất kỳ cách nào để buộc awk để hiển thị giá trị chính xác (chứ không phải là ký hiệu khoa học)? –

+0

Andrew, có một chức năng printf cho awk: http://www.gnu.org/software/gawk/manual/gawk.html#Printf –

1

Bạn có thể bắt đầu bằng cách chạy dữ liệu qua cut - ít nhất sẽ cắt các cột xuống.

Sau đó, bạn có thể đưa đường ống đó vào grep, loại bỏ số không.

Sau đó ... tốt, sau đó tôi không chắc chắn. Có thể đường ống đó đến bc. Nếu không, nó chắc chắn có thể được giao cho một kịch bản shell để thêm từng mục.

Nếu bạn sử dụng tr để thay đổi dòng mới (\n) để không gian (), và được truyền dẫn thông qua xargs vào kịch bản của bạn mà vòng cho đến khi không có nhiều đầu vào, thêm mỗi người, bạn có thể có một câu trả lời.

Vì vậy, một cái gì đó tương tự như sau:

cat <whatever> | cut -d'\t` -f7 | grep -v <appropriate-character-class> | tr '\n' ' ' | xargs script-that-adds-arguments 

tôi có thể có cut cờ hơi sai - nhưng man là bạn của bạn :)

2

Python Giải pháp

#!/usr/bin/env python 
text= file("the_file","r") 
total= 0 
for line in text: 
    data = line.split() 
    if data[0] in ('T', 'Shared', 'IPC'): continue 
    print line 
    segsize= int(data[6]) 
    total += segsize 
print total 

distro Linux Hầu hết có Python.

Nếu bạn muốn xử lý stdin như một phần của một pipline, sử dụng

import sys 
total = 0 
for line in sys.stdin: 
    ...etc... 

Nếu bạn muốn để giả định rằng luôn có 3 dòng tiêu đề:

import sys 
total = 0 
for line in sys.stdin.readlines()[3:]: 
    total += int(line.split()[6]) 
print total 

One-liner:

import sys; print sum([int(line.split()[6]) for line in sys.stdin.splitlines()[3:]]) 
1

Bạn có thể tra cứu nó trong bất kỳ tham chiếu awk trực tuyến nào:

ipcs | awk ' 
BEGIN { sum = 0 } 
/0x000000/ { sum = sum + $2 } 
END {print sum}' 
3

Tôi có một tập lệnh tiện ích chỉ cần thêm tất cả các cột. Nó thường dễ dàng, đủ để lấy một trong những bạn muốn từ đầu ra một dòng. Là tiền thưởng, một số hậu tố SI được công nhận.

#!/usr/bin/awk -f 
# Sum up numerical values by column (white-space separated) 
# 
# Usage: $0 [file ...] 
# 
# stern, 1999-2005 

{ 
    for(i = 1; i <= NF; ++i) { 
     scale = 1 
     if ($i ~ /[kK]$/) { scale = 1000 } 
     if ($i ~ /[mM]$/) { scale = 1000*1000 } 
     if ($i ~ /[gG]$/) { scale = 1000*1000*1000 } 
     col[i] += scale * $i; 
    } 
    if (NF > maxnf) maxnf = NF; 
} 

END { 
    for(i = 1; i <= maxnf; ++i) { printf " %.10g", col[i] } 
    print ""; 
} 

Ví dụ với lĩnh vực phân cách tùy chỉnh:

$ head /etc/passwd | addcol -F: 
0 0 45 39 0 0 0 
+0

# Cách sử dụng: $ 0 [tệp ...] <- Không có "-F" ... Bạn có thể làm rõ việc sử dụng không? Cờ nào được hỗ trợ? –

0

Cảm ơn Python one-liner trên !. Nó giúp tôi dễ dàng kiểm tra không gian đã sử dụng trên ổ đĩa của tôi. Đây là một vỏ hỗn hợp/Python một lớp lót, làm điều này - đếm không gian được sử dụng trên thiết bị/dev/sda tính bằng megabyte. Phải mất một thời gian, trước khi tôi phát hiện ra nó, vì vậy, có lẽ ai đó cũng thấy điều này hữu ích.

df -h -B 1M | grep dev/sda | tr -s ' '| cut -d' ' -f3 |python -c "import sys; print sum([int(num) for num in sys.stdin.readlines()])" 

hoặc nhiều Python/ít vỏ:

df -h -B 1M | python -c "import sys; print sum([int(l.split()[2]) for l in sys.stdin.readlines() if '/dev/sda' in l])" 

Cảm ơn một lần nữa!

12

tôi sẽ cố gắng để xây dựng một chuỗi tính toán và thức ăn nó để bc như sau:

  1. grep các dòng có chứa các con số
  2. sed đi tất cả các nhân vật trước (và sau) số trên mỗi dòng
  3. xargs kết quả (để nhận được một chuỗi số được phân tách bằng khoảng trắng)
  4. tr làm lệch các khoảng trống thành ký tự '+'
  5. cảm giác ngon miệng bc!

ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' + | bc

Trông như thế này là hơi dài hơn awk giải pháp , nhưng đối với tất cả mọi người không thể đọc được (và hiểu) lẻ đang awk này có thể được dễ dàng hơn để nắm bắt .. . :-)

Nếu bc không được cài đặt, bạn có thể sử dụng dấu ngoặc kép trong bước 5 ở trên để tính toán kết quả:

  • echo $(($(ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' +))) hoặc
  • SUM=$(($(ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' +))) hoặc
  • ((SUM=$(ipcs -mb | grep -w '^m ' | sed 's/^.*\s//' | xargs | tr ' ' +)))

Khoảng cách sau và trước dấu ngoặc kép là tùy chọn.

1

Tôi biết câu hỏi này có phần ngày, nhưng tôi không thể thấy câu trả lời "của tôi" ở đây, vì vậy tôi đã quyết định đăng bài.Tôi muốn đi với một sự kết hợp của

  • đuôi (để có được những dòng bạn cần)
  • tr (co lại xuống nhiều không gian consequitive để một)
  • cắt (để có được chỉ cột cần thiết)
  • dán (để nối mỗi dòng với một dấu +)
  • bc (để thực hiện tính toán thực tế)

ipcs không đưa ra một đầu ra trên hệ thống của tôi, vì vậy tôi sẽ chỉ giới thiệu nó với df:

# df 
Filesystem  1K-blocks Used Available Use% Mounted on 
rootfs   33027952 4037420 27312812 13%/
udev    10240  0  10240 0% /dev 
tmpfs    102108  108 102000 1% /run 
/dev/xvda1  33027952 4037420 27312812 13%/
tmpfs    5120  0  5120 0% /run/lock 
tmpfs    204200  0 204200 0% /run/shm 
/dev/xvda1  33027952 4037420 27312812 13% /var/www/clients/client1/web1/log 
/dev/xvda1  33027952 4037420 27312812 13% /var/www/clients/client1/web2/log 
/dev/xvda1  33027952 4037420 27312812 13% /var/www/clients/client1/web3/log 
/dev/xvda1  33027952 4037420 27312812 13% /var/www/clients/client1/web4/log 
/dev/xvda1  33027952 4037420 27312812 13% /var/www/clients/client2/web5/log 
/dev/xvda1  33027952 4037420 27312812 13% /var/www/clients/client2/web6/log 
# df | tail -n +2 | tr -s ' ' | cut -d ' ' -f 2 | paste -s -d+ | bc 
264545284 

Tôi biết làm tính đặc biệt này trên hệ thống của tôi không thực sự có ý nghĩa, nhưng nó cho thấy khái niệm này.

Tất cả các phần của giải pháp này đã được hiển thị trong các câu trả lời khác, nhưng không bao giờ trong kết hợp đó.

Các vấn đề liên quan