Cách hiệu quả để tạo nhiều tập tin


7

Tôi đã kiểm tra thư mục find đang lấy tối đa inodes và trong khi kiểm tra tôi đã chạy

touch test_{1..1391803}.txt

Nhưng nó gây ra lỗi cho tôi "-bash: /usr/bin/touch: Argument list too long", bây giờ tôi đang chạy dưới lệnh, nhưng có vẻ như nó sẽ mất thời gian của Hugh

ruby -e '1.upto(1391803) { |n| %x( touch "test_#{n}.txt" ) }'

Vì vậy, câu hỏi là: có cách nào để tạo nhiều tệp trong một khoảng thời gian nhỏ không? Tôi nên chạm vào 1 tệp lac trên mỗi vòng lặp hay cách nào tốt hơn?

Kết quả kiểm tra :

Số 1

[root@dc1 inode_test]# time seq 343409 | xargs touch

real    0m7.760s
user    0m0.525s
sys     0m4.385s

Số 2

[root@test-server inode_test]# time echo 'for (i=1;i<=343409;i++) i' | bc | xargs touch

real    0m8.781s
user    0m0.722s
sys     0m4.997s

số 3

[root@test-server inode_test]# time printf '%s ' {1..343409} | xargs touch

real    0m8.913s
user    0m1.144s
sys     0m4.541s

Số 4

[root@test-server inode_test]# time awk 'BEGIN {for (i=1; i<=343409; i++) {printf "" >> i; close(i)}}'

real    0m12.185s
user    0m2.005s
sys     0m6.057s

Số 5

[root@test-server inode_test]# time ruby -e '1.upto(343409) { |n| File.open("#{n}", "w") {} }'

real    0m12.650s
user    0m3.017s
sys     0m4.878s

Câu trả lời:


12

Giới hạn là về kích thước của các đối số khi thực hiện lệnh. Vì vậy, các tùy chọn là thực thi một lệnh có ít đối số hơn, ví dụ như xargsđể chạy các lô nhỏ hơn, tăng giới hạn ( ulimit -s 100000trên Linux), không thực thi bất cứ điều gì (thực hiện tất cả trong trình bao) hoặc xây dựng danh sách trong công cụ tạo các tập tin.

zsh, ksh93, bash:

printf '%s ' {1..1391803} | xargs touch

printfđược dựng sẵn, vì vậy không có exec, vì vậy giới hạn không đạt được. xargschia nhỏ danh sách các đối số được thông qua touchđể tránh phá vỡ giới hạn. Điều đó vẫn không hiệu quả lắm vì trước tiên, shell phải tạo toàn bộ danh sách (đặc biệt là chậm bash), lưu trữ nó trong bộ nhớ và sau đó in nó.

seq 1391803 | xargs touch

(giả sử bạn có một seqlệnh) sẽ hiệu quả hơn.

for ((i=1; i<=1391803; i++)); do : >> "$i"; done

Tất cả mọi thứ được thực hiện trong shell, không có danh sách lớn được lưu trữ trong bộ nhớ. Nên tương đối hiệu quả trừ có thể với bash.

POSIXly:

i=1; while [ "$i" -le 1391803 ]; do : >> "$i"; i=$(($i + 1)); done

echo 'for (i=1;i<=1391803;i++) i' | bc | xargs touch

awk 'BEGIN {for (i=1; i<=1391803; i++) {printf "" >> i; close(i)}}'

3

Bạn đang bị giới hạn bởi số lượng đối số tối đa touchcó thể xử lý. Đặt cược tốt nhất sẽ là sử dụng một vòng lặp. Bạn không cần ruby ​​để làm điều đó, mặc dù:

for i in $(seq 1391803); do touch test_${i}.txt; done

Một cách tiếp cận khác có thể là chia số thành nhiều phần, giả sử 100 và sau đó cho chúng ăn touchcùng một lúc:

i=1; while ((i<=1391803)); do touch $(seq $i $((i+99))); i=$((i+100)); done

Giới hạn không phải với touchnhưng với lệnh execve()gọi hệ thống (về kích thước tích lũy của các đối số và biến môi trường được truyền dọc theo lệnh gọi đó).
Stéphane Chazelas

+1 vì đây là tốc độ nhanh nhất, thậm chí nhanh hơn nếu bạn lặp lại các lệnh của đường ống song song. Giải pháp được chấp nhận sẽ mất hơn 1 giờ để tạo 10 triệu tệp của tôi, điều này đã thực hiện trong chưa đầy 1 phút
1084563

3

Trong ví dụ của bạn, Bash phàn nàn vì khi mở rộng test_{1..1391803}.txtnó kết thúc bằng một dòng lệnh đối số quá dài. Độ dài tối đa của dòng lệnh có thể được truyền cho lệnh được cố định bởi kernel, bởi vì lệnh exec gọi hệ thống chịu trách nhiệm bắt đầu các quy trình mới (trên thực tế, thay thế chương trình của một quy trình hiện tại bằng một lệnh khác) phải đặt các đối số đó vào ngăn xếp của quá trình và kích thước của ngăn xếp bị hạn chế.

Tôi nghĩ rằng cách hiệu quả nhất để làm điều này sẽ không bắt đầu một touchquy trình mới mỗi khi bạn muốn có một tệp.

Bạn có thể trong ruby ​​chẳng hạn:

ruby -e '1.upto(1391803) { |n| File.open("test_#{n}.txt", "w") {} }'

Bằng cách này, bạn chỉ bắt đầu một quy trình sẽ tạo tất cả các tệp mà không cần phải khởi chạy touchchương trình.

Lệnh này khởi chạy trình thông dịch ruby. Sau đó, ruby ​​xây dựng một vòng lặp trong phạm vi 1..1391803và với mỗi số, gọi hàm File.openthực hiện opencuộc gọi hệ thống với tên tệp được tạo với số đó. Khi khối sau File.opentrống, tệp sẽ bị đóng ngay lập tức.


bạn có thể vui lòng giải thích làm thế nào điều này làm việc?
Rahul Patil

Tôi cập nhật câu trả lời của tôi. Đừng ngần ngại hỏi nếu có bất kỳ nghi ngờ còn lại. :)
lgeorget
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.