Với find
, bạn có thể liệt kê đệ quy tất cả các tệp phù hợp với một tiêu chí nhất định, ví dụ như tên tệp.
for file in $(find . -type f -name "*.csv"); do cat "$file" >> /path/to/output.csv; done
Phá vỡ nó, find . -name "*.csv"
sẽ tìm thấy tất cả các tệp CSV từ thư mục hiện tại bạn đang ở ( .
) và vòng lặp sẽ chỉ lặp lại trên danh sách đó, nối thêm mọi thứ vào output.csv
tệp.
Nhưng: Tên tệp có dấu cách, ký tự toàn cầu và dòng mới có thể khó ở đây. Một giải pháp an toàn hơn là chỉ sử dụng exec
cho lệnh find.
find . -name "*.txt" -exec cat '{}' >> /path/to/output.csv ';'
Ở đây, '{}'
sẽ được thay thế bằng find với tên tệp. Đối với một câu hỏi dài về lý do tại sao điều này là và làm thế nào để phá vỡ vấn đề có thể được tìm thấy ở đây .
Bây giờ, nếu bạn muốn tạo một tệp CSV cho mỗi thư mục - xin lỗi, trước đây bạn không thấy điều đó - có lẽ tôi đã làm một cái gì đó như thế này:
for dir in $(find . -type d); do find $dir -maxdepth 1 -name "*.csv" -exec cat {} >> "$dir/out" ';'; mv "$dir/out" "$dir/merged.csv"; done
Mặc dù giải pháp của Franck dưới đây có lẽ hiệu quả hơn.
Tất nhiên, chú ý đến sự khác biệt giữa >
và >>
. Cái trước sẽ luôn cắt ngắn tập tin về độ dài bằng không trước khi ghi vào nó, trong khi cái sau sẽ chỉ nối vào tập tin.
Lý do tại sao cat *.csv > merged.csv
hoạt động của Haiti và tại sao trong vòng lặp của bạn, nó sẽ không hoạt động bởi vì shell sẽ mở rộng ký tự đại diện trước đó, vì vậy về cơ bản nó thấy:
cat file1.csv file2.csv file3.csv > merged.csv
Tất nhiên sẽ không ghi đè lên bất cứ điều gì.
$DIR
và$dir
không giống nhau