Fügen Sie in der Unix-Shell eine Zahlenspalte hinzu

197

Wenn files.txtich eine Liste der Dateien in habe , kann ich eine Liste ihrer Größen wie folgt erhalten:

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

was so etwas hervorbringt:

  151552
  319488
 1536000
  225280

Wie kann ich die Summe all dieser Zahlen ermitteln?

RichieHindle
quelle

Antworten:

382
... | paste -sd+ - | bc

ist die kürzeste, die ich gefunden habe (aus dem UNIX Command Line- Blog).

Bearbeiten: Das -Argument für Portabilität wurde hinzugefügt , danke @Dogbert und @Owen.

Todd Owen
quelle
Nett. Brauchen Sie die letzte - auch auf Solaris
Owen B
8
alias sum="paste -sd+ - | bc"zur Fertigstellung der Shell hinzugefügt, danke mate
slf
. . .| x=$(echo <(cat)); echo $((0+${x// /+}+0))Wenn Sie alle Bash die ganze Zeit wollen:
Qneill
13
@slf, pass auf, du bist gerade überladen/usr/bin/sum
qneill
3
Achtung, bcist auf einigen Systemen nicht verfügbar! awkAndererseits ist (glaube ich) für die POSIX-Konformität erforderlich.
vktec
154

Hier geht

cat files.txt | xargs ls -l | cut -c 23-30 | 
  awk '{total = total + $1}END{print total}'
Greg Reynolds
quelle
34
Die Verwendung von awk ist eine gute Idee, aber warum sollte man das behalten cut? Das ist eine vorhersehbare Spaltennummer, also benutze... | xargs ls -l | awk '{total = total + $5}{END{print total}'
dmckee --- Ex-Moderator Kätzchen
3
Sie haben natürlich Recht - es war einfacher, nur an das Ende dessen anzuhängen, was bereits da war :-)
Greg Reynolds
2
Eine Klammer zu viel in @ dmckees Antwort :)
Dr. Jan-Philip Gehrcke
7
Um dies etwas kürzer zu machen, könnten Sie total+=$1anstelle vontotal = total + $1
vktec
10

Anstatt cut zu verwenden, um die Dateigröße aus der Ausgabe von ls -l zu ermitteln , können Sie direkt Folgendes verwenden:

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

Awk interpretiert "$ 5" als fünfte Spalte. Dies ist die Spalte von ls -l , in der die Dateigröße angegeben ist.

Barun
quelle
10

cat funktioniert nicht, wenn in Dateinamen Leerzeichen vorhanden sind. Hier ist stattdessen ein Perl-Einzeiler.

perl -nle 'chomp; $x+=(stat($_))[7]; END{print $x}' files.txt
ALLES
quelle
8
python3 -c"import os; print(sum(os.path.getsize(f) for f in open('files.txt').read().split()))"

Oder wenn Sie nur die Zahlen summieren möchten, leiten Sie Folgendes ein:

python3 -c"import sys; print(sum(int(x) for x in sys.stdin))"
Collin Anderson
quelle
1
... | python -c'import sys; print(sum(int(x) for x in sys.stdin))'wenn Python 2 Ende dieses Jahres verschwindet.
Gleichnamig
don @ oysters: ~ / Dokumente $ cat tax | python3 -c "sys importieren; print (sum (int (x) für x in sys.stdin))" Traceback (letzter Aufruf zuletzt): Datei "<string>", Zeile 1, in <module> File "<string > ", Zeile 1, in <genexpr> ValueError: ungültiges Literal für int () mit Basis 10: '\ n'
hell
5

TMTWWTDI : Perl hat einen Dateigrößenoperator (-s)

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

Das ganze ls -l und dann geschnitten ist ziemlich verworren, wenn Sie stat haben . Es ist auch anfällig für das genaue Format von ls -l (es hat nicht funktioniert, bis ich die Spaltennummern für cut geändert habe )

Auch die nutzlose Verwendung von Katze behoben .

<files.txt  xargs stat -c %s | paste -sd+ - | bc
Hugo González Monteverde
quelle
2
Huh. Ich benutze Unix seit 32 Jahren und wusste nie, dass dies <infile commanddasselbe ist (und in einer besseren Reihenfolge als) command <infile.
Camille Goudeseune
5

Wenn Sie bc nicht installiert haben, versuchen Sie es

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

anstatt

... | paste -sd+ - | bc

$( ) <- Gibt den Wert für die Ausführung des Befehls zurück

$(( 1+2 )) <- gibt die ausgewerteten Ergebnisse zurück

echo <- Echo auf dem Bildschirm

MrMobileMan
quelle
4

Sie können das folgende Skript verwenden, wenn Sie nur Shell-Skripte ohne awk oder andere Interpreter verwenden möchten:

#!/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
Andre Miller
quelle
3

Ich würde stattdessen "du" verwenden.

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

Wenn Sie nur die Nummer wollen:

cat files.txt | xargs du -c | tail -1 | awk '{print $1}'
MichaelJones
quelle
5
Festplattennutzung! = Dateigröße. du meldet die Datenträgernutzung.
0x6adb015
4
Ich denke, der Schalter -b bringt dich dazu, das zu tun, was ich brauche.
RichieHindle
@ 0x6adb015 Gute Kenntnisse. Danke, ich hatte es nicht bemerkt.
MichaelJones
3
Dies ist eine nützliche Antwort aus dem spezifischen Grund, warum das OP die Spalte mit den Zahlen hinzufügen wollte, aber für den allgemeinen Fall des Hinzufügens von Zahlen ist sie nicht ausreichend. (Ich benutze "du" die ganze Zeit selbst, aber ich bin hierher gekommen, um nach Kommandozeilenmathematik zu suchen. :-))
Michael H.
12
Dies funktioniert nicht, wenn files.txtes groß ist. Wenn die Anzahl der Argumente, xargsdie weitergeleitet werden, einen bestimmten Schwellenwert erreicht, werden sie über mehrere Aufrufe an aufgeteilt du. Die am Ende angezeigte Summe ist die Summe nur für den letzten Anruf bei du, nicht für die gesamte Liste.
Matthew Simoneau
3

In ksh:

echo " 0 $(ls -l $(<files.txt) | awk '{print $5}' | tr '\n' '+') 0" | bc
Sanjaya R.
quelle
1
Gut, um das Überspringen cutvon zu lernen, aber Sie ignorieren die Fähigkeit von awks, die Mathematik zu machen ...
dmckee --- Ex-Moderator-Kätzchen
1

Pipe to gawk:

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

Hier ist meins

cat files.txt | xargs ls -l | cut -c 23-30 | sed -e :a -e '$!N;s/\n/+/;ta' | bc
Jason Punyon
quelle
6
+1 für ein für alle Mal zu beweisen, dass es hässlichere Sprachen als Perl gibt :)
bdonlan
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. *
Steven Bensky
quelle
1

Ich benutze gerne ....

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

Sie zeigen die Summe jeder Zeile ...

Anwendung über diese Situation:

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

Total ist der letzte Wert ...

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

Sie können die awk verwenden, um dasselbe zu tun, und sogar die Nicht-Ganzzahlen überspringen

$ cat files.txt
1
2.3
3.4
ew
1

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

oder Sie können den Befehl ls verwenden und die vom Menschen lesbare Ausgabe berechnen

$ 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
ck reddy
quelle
Sie brauchen nicht einmal Pfeife: awk '{ total += $1} END {print total}' files.txtist schneller
bmv
0

Meiner Meinung nach ist die einfachste Lösung dafür der Unix-Befehl "expr":

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

Pure Bash

total=0; for i in $(cat files.txt | xargs ls -l | cut -c 23-30); do 
total=$(( $total + $i )); done; echo $total
John Kloian
quelle
0
sizes=( $(cat files.txt | xargs ls -l | cut -c 23-30) )
total=$(( $(IFS="+"; echo "${sizes[*]}") ))

Oder Sie können sie einfach zusammenfassen, während Sie die Größen lesen

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

Wenn Sie sich nicht für Bissgrößen und Blöcke interessieren, ist das in Ordnung

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

Wenn Sie R haben, können Sie verwenden:

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

Da ich mit R vertraut bin, habe ich tatsächlich mehrere Aliase für solche Dinge, damit ich sie verwenden kann, bashohne mich an diese Syntax erinnern zu müssen. Zum Beispiel:

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

was lass mich machen

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

Inspiration: Gibt es eine Möglichkeit, Min, Max, Median und Durchschnitt einer Liste von Zahlen in einem einzigen Befehl zu ermitteln?

merv
quelle