2012-05-09 39 views
163

Có thể ai đó vui lòng cung cấp mã để làm như sau: Giả sử có một thư mục tệp, tất cả đều cần được chạy qua chương trình. Chương trình đưa ra kết quả theo tiêu chuẩn. Tôi cần một kịch bản sẽ đi vào một thư mục, thực hiện lệnh trên mỗi tập tin, và concat đầu ra thành một tập tin đầu ra lớn.Tập lệnh Bash để thực hiện lệnh trên tất cả các tệp trong một thư mục

Ví dụ, để chạy các lệnh trên 1 file:

$ cmd [option] [filename] > results.out 
+3

Tôi muốn để thêm vào câu hỏi. Nó có thể được thực hiện bằng cách sử dụng xargs? ví dụ: 'ls | xargs cmd [options] {tên tập tin được đặt vào đây tự động bởi xargs} [more arguments]> results.out' –

+0

Nó có thể, nhưng bạn có thể [không muốn sử dụng 'ls'] (http: //mywiki.wooledge. org/ParsingLs) để điều khiển 'xargs'. Nếu 'cmd' được viết một cách thành thạo, có lẽ bạn chỉ cần thực hiện' cmd '. – tripleee

Trả lời

244

Mã bash sau sẽ vượt qua $ file chỉ huy nơi $ file sẽ đại diện cho tất cả các tập tin trong/dir

for file in /dir/* 
do 
    cmd [option] "$file" >> results.out 
done 

Ví dụ

[email protected] ~/foo $ touch foo.txt bar.txt baz.txt 
[email protected] ~/foo $ for i in *.txt; do echo "hello $i"; done 
hello bar.txt 
hello baz.txt 
hello foo.txt 
+13

Nếu không có tệp nào tồn tại trong'/dir/', thì vòng lặp vẫn chạy một lần với giá trị '*' cho' $ file', có thể không mong muốn. Để tránh điều này, hãy kích hoạt nullglob trong suốt vòng lặp. Thêm dòng này trước vòng lặp 'shopt -s nullglob' và dòng này sau vòng lặp' shopt -u nullglob #revert nullglob trở về trạng thái mặc định bình thường'. –

+29

+1, Và nó chỉ chi phí cho tôi bộ sưu tập hình nền của tôi. tất cả mọi người sau tôi, sử dụng doublequotes. "$ file" – Behrooz

+0

Nếu tập tin đầu ra giống nhau bên trong vòng lặp, nó sẽ hiệu quả hơn để chuyển hướng bên ngoài vòng lặp 'done> results.out' (và có thể sau đó bạn có thể ghi đè thay vì nối thêm, như tôi đã giả định ở đây). – tripleee

112

Làm thế nào về điều này:

find /some/directory -maxdepth 1 -type f -exec cmd option {} \; > results.out 
  • -maxdepth 1 luận ngăn chặn tìm từ đệ quy giảm dần vào bất kỳ thư mục con. (Nếu bạn muốn các thư mục lồng nhau đó được xử lý, bạn có thể bỏ qua điều này.)
  • -type -f chỉ định rằng chỉ các tệp thuần tuý sẽ được xử lý.
  • -exec cmd option {} nói với nó để chạy cmd với quy định option cho mỗi tập tin được tìm thấy, với tên tập tin thay thế cho {}
  • \; biểu thị sự kết thúc của lệnh.
  • Cuối cùng, sản lượng từ tất cả các cmd hành cá nhân được chuyển đến results.out

Tuy nhiên, nếu bạn quan tâm đến thứ tự mà các tập tin được xử lý, bạn có thể được tốt hơn off viết một vòng lặp. Tôi nghĩ rằng find xử lý các tệp theo thứ tự inode (mặc dù tôi có thể sai về điều đó), có thể không phải là những gì bạn muốn.

+1

Đây là cách xử lý tệp chính xác. Sử dụng vòng lặp for là dễ bị lỗi do nhiều lý do. Việc sắp xếp cũng có thể được thực hiện bằng cách sử dụng các lệnh khác như 'stat' và' sort', tùy thuộc vào tiêu chí sắp xếp. – tuxdna

+0

nếu tôi muốn chạy hai lệnh, tôi sẽ liên kết chúng như thế nào sau tùy chọn '-exec'? Tôi có phải quấn chúng trong dấu nháy đơn hay gì đó không? – frei

+0

'find' luôn là lựa chọn tốt nhất khiến bạn có thể lọc theo mẫu tên tệp với tùy chọn' -name' và bạn có thể làm điều đó trong một lệnh duy nhất. –

22

tôi đang làm điều này trên pi mâm xôi của tôi từ dòng lệnh bằng cách chạy:

for i in *;do omxplayer "$i";done 
1

tôi cần phải sao chép tất cả các file .md từ một thư mục này sang thư mục khác, vì vậy đây là những gì tôi đã làm.

for i in **/*.md;do mkdir -p ../docs/"$i" && rm -r ../docs/"$i" && cp "$i" "../docs/$i" && echo "$i -> ../docs/$i"; done

Đó là khá khó khăn để đọc, vì vậy cho phép phá vỡ nó xuống.

cd đầu tiên vào thư mục với các tập tin của bạn,

for i in **/*.md; cho mỗi tập tin trong mô hình của bạn

mkdir -p ../docs/"$i" làm cho thư mục đó trong một thư mục tài liệu bên ngoài thư mục chứa tập tin của bạn. Tạo thư mục bổ sung có cùng tên với tệp đó.

rm -r ../docs/"$i" loại bỏ thêm các thư mục được tạo ra như là một kết quả của mkdir -p

cp "$i" "../docs/$i" Sao chép các tập tin thực tế

echo "$i -> ../docs/$i" Echo gì bạn đã làm

; done sống hạnh phúc mãi mãi về sau

1

Một cách nhanh chóng và cách bẩn thỉu đôi khi được thực hiện công việc là:

Ví dụ để tìm số dòng trong tất cả các file trong thư mục hiện tại, bạn có thể làm:

find . | xargs wc -l 
Các vấn đề liên quan