أقصر أمر لحساب مجموع عمود الإخراج على يونكس؟

StackOverflow https://stackoverflow.com/questions/295781

  •  08-07-2019
  •  | 
  •  

سؤال

أنا متأكد من أن هناك طريقة سريعة وسهلة لحساب مجموع عمود من القيم على أنظمة يونكس (باستخدام شيء مثل awk أو xargs ربما)، ولكن كتابة برنامج نصي لتحليل الصفوف سطرًا تلو الآخر هو الشيء الوحيد الذي يتبادر إلى الذهن في الوقت الحالي.

على سبيل المثال، ما هي أبسط طريقة لتعديل الأمر أدناه لحساب وعرض الإجمالي لعمود SEGSZ (70300)؟

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
هل كانت مفيدة؟

المحلول

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

وأو بدون الذيل:

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

وعن طريق AWK مع قبل الميلاد للحصول على نتائج طويلة التعسفية (ائتمانات لJouni K.):

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

نصائح أخرى

سأحاول إنشاء سلسلة حسابية وإطعامها قبل الميلاد على النحو التالي:

  1. grep الخطوط التي تحتوي على الأرقام
  2. سيد قم بإزالة جميع الأحرف قبل (وبعد) الرقم الموجود في كل سطر
  3. com.xargs النتيجة (للحصول على سلسلة من الأرقام مفصولة بالفراغات)
  4. آر قم بترجمة الفراغات إلى أحرف "+".
  5. شهية طيبة قبل الميلاد!

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

يبدو أن هذا أطول قليلاً من محرج الحل، ولكن لكل من لا يستطيع القراءة (وفهم) الغريب محرج قد يكون هذا الرمز أسهل في الفهم ...:-)

لو قبل الميلاد لم يتم تثبيته، يمكنك استخدام الأقواس المزدوجة في الخطوة 5 أعلاه لحساب النتيجة:

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

يعد التباعد بعد وقبل الأقواس المزدوجة أمرًا اختياريًا.

ولدي النصي الأداة التي تضيف ببساطة <م> جميع الأعمدة. انها عادة ما تكون السهل بما فيه الكفاية لانتزاع واحدة تريد من إخراج سطر واحد. على سبيل المكافأة، يتم التعرف على بعض SI-اللواحق.

#!/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 "";
}

وعلى سبيل المثال مع فاصل حقل مخصص:

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

وبيثون الحل

#!/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

وتوزيعات لينكس أفضل لها بيثون.

إذا كنت تريد معالجة ستدين كجزء من pipline، استخدم

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

إذا كنت تريد أن نفترض أن هناك دائما خطوط 3 الرأس:

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

وبطانة الأول:

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

أعلم أن هذا السؤال قديم إلى حد ما، لكن لا يمكنني رؤية إجابتي هنا، لذلك قررت النشر بالرغم من ذلك.سأذهب مع مزيج من

  • الذيل (للحصول على الخطوط التي تحتاجها)
  • tr (لتقليص مسافات متتالية متعددة إلى واحدة)
  • قطع (للحصول على العمود المطلوب فقط)
  • لصق (لربط كل سطر بـ a + لافتة)
  • قبل الميلاد (للقيام بالحساب الفعلي)

ipcs لا يعطي مخرجات على نظامي، لذا سأعرضه فقط 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

أعلم أن إجراء هذه العملية الحسابية على نظامي ليس له معنى حقًا، ولكنه يوضح المفهوم.

لقد تم عرض جميع أجزاء هذا الحل في الإجابات الأخرى، ولكن لم يتم عرضها أبدًا في تلك المجموعة.

هل يمكن أن تبدأ عن طريق تشغيل البيانات من خلال cut - التي من شأنها أن ما لا يقل عن تقليم الأعمدة أسفل.

ويجب أن تكون ثم قادرا على الأنابيب التي في grep، وتجريد المغادرة غير numerics.

وبعد ذلك ... حسنا، ثم لست متأكدا. قد يكون من الممكن أن الأنابيب إلى bc. إن لم يكن، فإنه يمكن بالتأكيد أن تسلم إلى شيل لإضافة كل عنصر.

إذا كنت تستخدم tr لتغيير أسطر جديدة (\n) إلى مسافات ()، والأنابيب أنه من خلال xargs في السيناريو الخاص بك حلقات حتى لا توجد المزيد من المدخلات، وأضاف كل واحد، قد يكون لديك الحل.

وهكذا، شيء أقرب إلى ما يلي:

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

وربما أكون قد أعلام cut الخطأ قليلا - ولكن man صديقك:)

هل يمكن البحث عنه في أي إشارة AWK على الانترنت:

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

وشكرا لبيثون بطانة واحدة فوق !. انها ساعدتني لمن السهل التحقق من المساحة المستخدمة على القرص بلدي. هنا هو قذيفة المختلطة / بيثون أونيلينير، أن تفعل هذا - تهمة استخدام مساحة على الجهاز / ديف / حزب العمل الديمقراطي في ميغا بايت. استغرق الأمر مني بعض الوقت، قبل وجدت بها، لذلك، ربما هناك من يرى هذا مفيد للغاية.

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()])"

وأو أكثر بيثون / أقل قذيفة:

 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])"

وشكرا مرة أخرى!

لجمع القيم في عمود يمكنك استخدام GNU datamash. منذ الأسطر الأربعة الأولى لا تحتوي على القيم التي تريد خلاصة القول، نحن إزالتها مع tail +4.

ipcs -mb  | tail +4 | datamash -W sum 7

والخيار -W يحدد محدد الحقل إلى (ربما متعددة) الفراغات.

إذا كان لديك، أعمدة متعددة المحددة التي تريد جمع، يمكنك استخدام:

input_command | awk '{s1+=$1;s2+=$2;s3+=$3;s4+=$4;s5+=$5}END{print s1,s2,s3,s4,s5}'

والتي ستعمل إذا كنت تريد جمع أعمدة 1-5.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top