Unix kabuğuna bir sayı sütunu ekleyin


198

Dosyaların bir listesi verildiğinde files.txt, boyutlarının bir listesini şöyle alabilirim:

cat files.txt | xargs ls -l | cut -c 23-30

ki böyle bir şey üretir:

  151552
  319488
 1536000
  225280

Tüm bu sayıların toplamını nasıl alabilirim ?

Yanıtlar:


383
... | paste -sd+ - | bc

bulduğum en kısa olanı ( UNIX Komut Satırı blogundan).

Düzenleme:- taşınabilirlik argümanı ekledi , teşekkürler @Dogbert ve @Owen.


Güzel. Sonuncu - Solaris'te de
Owen B

8
alias sum="paste -sd+ - | bc"mermi tamamlanmasına eklendi, teşekkürler dostum
slf

. . .| x=$(echo <(cat)); echo $((0+${x// /+}+0))her zaman bash istiyorsanız:
qneill

13
@slf, dikkat, sen sadece aşırı/usr/bin/sum
qneill

3
Dikkat, bcbazı sistemlerde mevcut değildir! awkdiğer yandan POSIX uyumluluğu için gerekli olduğuna inanıyorum.
vktec

154

İşte gidiyor

cat files.txt | xargs ls -l | cut -c 23-30 | 
  awk '{total = total + $1}END{print total}'

34
Awk kullanmak iyi bir fikirdir, ama neden cut? Bu tahmin edilebilir bir sütun numarasıdır, bu yüzden kullanın... | xargs ls -l | awk '{total = total + $5}{END{print total}'
dmckee --- eski moderatör yavru kedi

3
Tabii ki haklısın
Greg Reynolds

2
@ Dmckee'nin cevabında bir parantez çok fazla :)
Dr.Jan-Philip Gehrcke

7
Bunu biraz daha kısaltmak total+=$1içintotal = total + $1
vktec

10

Ls -l çıktısından dosya boyutunu almak için cut kullanmak yerine, doğrudan kullanabilirsiniz:

$ cat files.txt | xargs ls -l | awk '{total += $5} END {print "Total:", total, "bytes"}'

Awk "5 $" ı beşinci sütun olarak yorumlar. Bu, ls -l sütununun size dosya boyutunu veren sütundur .


10

dosya adlarında boşluk varsa kedi çalışmaz. bunun yerine perl bir astar var.

perl -nle 'chomp; $x+=(stat($_))[7]; END{print $x}' files.txt

8
python3 -c"import os; print(sum(os.path.getsize(f) for f in open('files.txt').read().split()))"

Veya sadece sayıları toplamak istiyorsanız, aşağıdakileri yapın:

python3 -c"import sys; print(sum(int(x) for x in sys.stdin))"

1
... | python -c'import sys; print(sum(int(x) for x in sys.stdin))'python 2 bu yılın sonunda kaybolduğunda.
İsimsiz

don @ oysters: ~ / Belgeler $ kedi vergisi | python3 -c "import sys; print (sys.stdin içinde x için sum (int (x)))" Traceback (en son çağrı son): "<string>" dosyası, satır 1, <module> File "<string >", satır 1 'de <genexpr> ValueError: temel 10 int () geçersiz hazır: '\ n'
parlak don

5

TMTWWTDI : Perl'in bir dosya boyutu operatörü var (-s)

perl -lne '$t+=-s;END{print $t}' files.txt

5

Bütün ls -l ve sen varken daha sonra kesim yerine dolambaçlı edilir , stat . Ayrıca ls -l'nin tam biçimine karşı da savunmasızdır ( kesim için sütun numaralarını değiştirene kadar çalışmadı )

Ayrıca, kedinin yararsız kullanımı düzeltildi .

<files.txt  xargs stat -c %s | paste -sd+ - | bc

2
Huh. Unix'i 32 yıldır kullanıyorum ve <infile commandbunun aynı olduğunu (ve daha iyi bir sırayla) bilmiyordum command <infile.
Camille Goudeseune

5

bc kurulu değilse, deneyin

echo $(( $(... | paste -sd+ -) ))

onun yerine

... | paste -sd+ - | bc

$( ) <- komutun yürütülmesinin değerini döndür

$(( 1+2 )) <- değerlendirilen sonuçları döndür

echo <- ekrana yansıtır


4

Sadece awk veya diğer tercümanlar olmadan kabuk komut dosyası kullanmak istiyorsanız, aşağıdaki komut dosyasını kullanabilirsiniz:

#!/bin/bash

total=0

for number in `cat files.txt | xargs ls -l | cut -c 23-30`; do
   let total=$total+$number
done

echo $total

3

Bunun yerine "du" kullanırdım.

$ cat files.txt | xargs du -c | tail -1
4480    total

Sadece numarayı istiyorsanız:

cat files.txt | xargs du -c | tail -1 | awk '{print $1}'

5
Disk kullanımı! = Dosya boyutu. du disk kullanımını bildirir.
0x6adb015

4
Bence -b anahtarı du gerekeni yapar.
RichieHindle

@ 0x6adb015 İyi bilgi. Teşekkür etmedim.
MichaelJones

3
Bu, OP'nin sayıların sütununu eklemesini istemesinin özel nedeni için yararlı bir cevaptır, ancak genel sayı ekleme davası için yetersiz kalır. (Ben her zaman "du" kullanıyorum, ama buraya komut satırı matematik aramaya geldim. :-))
Michael H.

12
Bu files.txtbüyük olduğunda çalışmaz . Pipolanan argüman sayısı xargsbelirli bir eşiğe ulaşırsa, bunları birden fazla çağrıyla keser du. Sonda gösterilen toplam du, tüm listenin değil, yalnızca son aramanın toplamıdır .
Matthew Simoneau


1

Gawk için boru:

 cat files.txt | xargs ls -l | cut -c 23-30 | gawk 'BEGIN { sum = 0 } // { sum = sum + $0 } END { print sum }'


1
#
#       @(#) addup.sh 1.0 90/07/19
#
#       Copyright (C) <heh> SjB, 1990
#       Adds up a column (default=last) of numbers in a file.
#       95/05/16 updated to allow (999) negative style numbers.


case $1 in

-[0-9])

        COLUMN=`echo $1 | tr -d -`

        shift

;;

*)

        COLUMN="NF"

;;

esac

echo "Adding up column .. $COLUMN .. of file(s) .. $*"

nawk  ' OFMT="%.2f"                                       # 1 "%12.2f"

        { x = '$COLUMN'                                   # 2

          neg = index($x, "$")                            # 3

          if (neg > 0) X = gsub("\\$", "", $x)

          neg = index($x, ",")                            # 4

          if (neg > 1) X = gsub(",", "", $x)

          neg = index($x, "(")                            # 8 neg (123 & change

          if (neg > 0) X = gsub("\\(", "", $x)

          if (neg > 0) $x = (-1 * $x)                     # it to "-123.00"

          neg = index($x, "-")                            # 5

          if (neg > 1) $x = (-1 * $x)                     # 6

          t += $x                                         # 7

          print "x is <<<", $x+0, ">>> running balance:", t

        } ' $*


# 1.  set numeric format to eliminate rounding errors
# 1.1 had to reset numeric format from 12.2f to .2f 95/05/16
#     when a computed number is assigned to a variable ( $x = (-1 * $x) )
#     it causes $x to use the OFMT so -1.23 = "________-1.23" vs "-1.23"
#     and that causes my #5 (negative check) to not work correctly because
#     the index returns a number >1 and to the neg neg than becomes a positive
#     this only occurs if the number happened to b a "(" neg number
# 2.  find the field we want to add up (comes from the shell or defaults
#     to the last field "NF") in the file
# 3.  check for a dollar sign ($) in the number - if there get rid of it
#     so we may add it correctly - $12 $1$2 $1$2$ $$1$$2$$ all = 12
# 4.  check for a comma (,) in the number - if there get rid of it so we
#     may add it correctly - 1,2 12, 1,,2 1,,2,, all = 12   (,12=0)
# 5.  check for negative numbers
# 6.  if x is a negative number in the form 999- "make" it a recognized
#     number like -999 - if x is a negative number like -999 already
#     the test fails (y is not >1) and this "true" negative is not made
#     positive
# 7.  accumulate the total
# 8.  if x is a negative number in the form (999) "make it a recognized
#     number like -999
# * Note that a (-9) (neg neg number) returns a postive
# * Mite not work rite with all forms of all numbers using $-,+. etc. *

1

Kullanmayı seviyorum ....

echo "
1
2
3 " | sed -e 's,$, + p,g' | dc 

her satırın toplamını gösterecekler ...

bu durum üzerinden başvuru yapmak:

ls -ld $(< file.txt) | awk '{print $5}' | sed -e 's,$, + p,g' | dc 

Toplam son değerdir ...


1
cat files.txt | awk '{ total += $1} END {print total}'

Awk kullanarak tamsayı olmayanları bile atlar

$ cat files.txt
1
2.3
3.4
ew
1

$ cat files.txt | awk '{ total += $1} END {print total}'
7.7

veya ls komutunu kullanabilir ve insan tarafından okunabilir çıktıyı hesaplayabilirsiniz

$ ls -l | awk '{ sum += $5} END  {hum[1024^3]="Gb"; hum[1024^2]="Mb"; hum[1024]="Kb"; for (x=1024^3; x>=1024; x/=1024) { if (sum>=x) { printf "%.2f %s\n",sum/x,hum[x]; break; } } if (sum<1024) print "1kb"; }'
15.69 Mb

$ ls -l *.txt | awk '{ sum += $5} END  {hum[1024^3]="Gb"; hum[1024^2]="Mb"; hum[1024]="Kb"; for (x=1024^3; x>=1024; x/=1024) { if (sum>=x) { printf "%.2f %s\n",sum/x,hum[x]; break; } } if (sum<1024) print "1kb"; }'
2.10 Mb

Hatta boruya bile ihtiyacınız yok: Daha awk '{ total += $1} END {print total}' files.txthızlı
BMV

0

Bence, bunun en basit çözümü "expr" unix komutudur:

s=0; 
for i in `cat files.txt | xargs ls -l | cut -c 23-30`
do
   s=`expr $s + $i`
done
echo $s

0

Saf bash

total=0; for i in $(cat files.txt | xargs ls -l | cut -c 23-30); do 
total=$(( $total + $i )); done; echo $total

0
sizes=( $(cat files.txt | xargs ls -l | cut -c 23-30) )
total=$(( $(IFS="+"; echo "${sizes[*]}") ))

Veya boyutları okurken onları toplayabilirsiniz

declare -i total=0
while read x; total+=x; done < <( cat files.txt | xargs ls -l | cut -c 23-30 )

Isırık büyüklükleri ve blokları umursamıyorsanız, o zaman sadece

declare -i total=0
while read s junk; total+=s; done < <( cat files.txt | xargs ls -s )

0

R'niz varsa şunları kullanabilirsiniz:

> ... | Rscript -e 'print(sum(scan("stdin")));'
Read 4 items
[1] 2232320

R ile rahat olduğum için, aslında böyle şeyler için birkaç takma adım var, bu yüzden bashbu sözdizimini hatırlamak zorunda kalmadan kullanabilirim. Örneğin:

alias Rsum=$'Rscript -e \'print(sum(scan("stdin")));\''

hangi yapalım

> ... | Rsum
Read 4 items
[1] 2232320

İlham: Tek bir komutta sayı listesinin min, maks, medyan ve ortalamasını almanın bir yolu var mı?

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.