Thêm một cột số ở vỏ Unix


198

Đưa ra một danh sách các tập tin files.txt, tôi có thể nhận được một danh sách các kích thước của chúng như thế này:

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

sản xuất một cái gì đó như thế này:

  151552
  319488
 1536000
  225280

Làm thế nào tôi có thể có được tổng số của tất cả những con số đó?

Câu trả lời:


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

là cái ngắn nhất tôi tìm thấy (từ blog Dòng lệnh UNIX ).

Chỉnh sửa: đã thêm -đối số cho tính di động, cảm ơn @Dogbert và @Owen.


Đẹp. Cũng cần cuối cùng - trên Solaris
Owen B

8
alias sum="paste -sd+ - | bc"được thêm vào hoàn thành shell, cảm ơn bạn đời
slf

. . .| x=$(echo <(cat)); echo $((0+${x// /+}+0))nếu bạn muốn tất cả bash mọi lúc:
qneill

13
@slf, coi chừng, bạn vừa quá tải/usr/bin/sum
qneill

3
Coi chừng, bckhông có sẵn trên một số hệ thống! awk, mặt khác là (tôi tin) cần thiết cho việc tuân thủ POSIX.
vktec

154

Ở đây đi

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

34
Sử dụng awk là một ý tưởng tốt, nhưng tại sao giữ cut? Đó là số cột có thể dự đoán được, vì vậy hãy sử dụng... | xargs ls -l | awk '{total = total + $5}{END{print total}'
dmckee --- ex-moderator mèo con

3
Tất nhiên bạn đã đúng - việc thêm vào phần cuối của những gì đã có là dễ dàng hơn :-)
Greg Reynold

2
Một khung quá nhiều trong câu trả lời của @ dmckee :)
Tiến sĩ Jan-Philip Gehrcke

7
Để làm cho điều này ngắn hơn một chút, bạn có thể sử dụng total+=$1thay vìtotal = total + $1
vktec

10

Thay vì sử dụng cắt để lấy kích thước tệp từ đầu ra của ls -l , bạn có thể sử dụng trực tiếp:

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

Awk diễn giải "$ 5" là cột thứ năm. Đây là cột từ ls -l cung cấp cho bạn kích thước tệp.


10

mèo sẽ không hoạt động nếu có không gian trong tên tập tin. đây là một perl một lót thay thế.

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

Hoặc nếu bạn chỉ muốn tính tổng các số, hãy chuyển thành:

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))'khi python 2 biến mất vào cuối năm nay.
Eponymous

don @ hàu: ~ / Tài liệu $ cat thuế | python3 -c "import sys; print (sum (int (x) cho x in sys.stdin))" TracBack (cuộc gọi gần đây nhất vừa qua): Tệp "<chuỗi>", dòng 1, trong <module> Tệp "<chuỗi > ", dòng 1, trong <genexpr> ValueError: chữ không hợp lệ cho int () với cơ sở 10: '\ n'
don sáng


5

Toàn bộ ls -l và sau đó cắt khá phức tạp khi bạn có stat . Nó cũng dễ bị định dạng chính xác của ls -l (nó không hoạt động cho đến khi tôi thay đổi số cột để cắt )

Ngoài ra, cố định việc sử dụng mèo vô dụng .

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

2
Huh. Đã sử dụng Unix trong 32 năm và không bao giờ biết điều đó <infile commandgiống như (và theo thứ tự tốt hơn) command <infile.
Camille Goudeseune

5

nếu bạn chưa cài đặt bc, hãy thử

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

thay vì

... | paste -sd+ - | bc

$( ) <- trả về giá trị thực thi lệnh

$(( 1+2 )) <- trả về kết quả được đánh giá

echo <- dội lại màn hình


4

Bạn có thể sử dụng tập lệnh sau nếu bạn chỉ muốn sử dụng tập lệnh shell mà không có awk hoặc các trình thông dịch khác:

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

Tôi sẽ sử dụng "du" thay thế.

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

Nếu bạn chỉ muốn số:

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

5
Sử dụng đĩa! = Kích thước của tệp. du báo cáo sử dụng đĩa.
0x6adb015

4
Tôi nghĩ rằng công tắc -b làm cho du làm những gì tôi cần.
RichieHulum

@ 0x6adb015 Kiến thức tốt. Cảm ơn tôi đã không nhận ra.
MichaelJones

3
Đó là một câu trả lời hữu ích cho lý do cụ thể tại sao OP muốn cột số được thêm vào, nhưng đối với trường hợp thêm số chung, nó bị thiếu. (Bản thân tôi sử dụng "du" mọi lúc, nhưng tôi đến đây để tìm kiếm toán học dòng lệnh. :-))
Michael H.

12
Điều này sẽ không hoạt động khi files.txtlớn. Nếu số lượng đối số được dẫn xargsđến ngưỡng nhất định, nó sẽ phá vỡ chúng qua nhiều cuộc gọi đến du. Tổng số hiển thị ở cuối là tổng số cho lần gọi cuối cùng du, không phải toàn bộ danh sách.
Matthew Simoneau


1

Ống để trố mắt:

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

1

Đây là của tôi

cat files.txt | xargs ls -l | cut -c 23-30 | sed -e :a -e '$!N;s/\n/+/;ta' | bc

6
+1 để chứng minh một lần và cho tất cả những ngôn ngữ xấu hơn perl :)
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. *

1

Tôi thích sử dụng ....

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

họ sẽ hiển thị tổng của từng dòng ...

áp dụng trong tình huống này:

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

Tổng là giá trị cuối cùng ...


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

Bạn có thể sử dụng awk để làm tương tự, thậm chí bỏ qua các số nguyên không

$ cat files.txt
1
2.3
3.4
ew
1

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

hoặc bạn có thể sử dụng lệnh ls và tính toán đầu ra của con người

$ 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

Bạn thậm chí không cần đường ống: awk '{ total += $1} END {print total}' files.txtnhanh hơn
bmv

0

Theo tôi, giải pháp đơn giản nhất cho điều này là lệnh "expr" unix:

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

0

Bash tinh khiết

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[*]}") ))

Hoặc bạn chỉ có thể tổng hợp chúng khi bạn đọc kích thước

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

Nếu bạn không quan tâm đến kích thước và khối cắn là OK, thì chỉ cần

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

0

Nếu bạn có R, bạn có thể sử dụng:

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

Vì tôi cảm thấy thoải mái với R, tôi thực sự có một số bí danh cho những thứ như thế này để tôi có thể sử dụng chúng bashmà không cần phải nhớ cú pháp này. Ví dụ:

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

mà hãy để tôi làm

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

Cảm hứng: Có cách nào để lấy min, max, median và trung bình của một danh sách các số trong một lệnh không?

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.