Làm thế nào để di chuyển tất cả các thư mục anh chị em vào một thư mục?


6

Tôi xin lỗi rằng đây có vẻ là một câu hỏi ngớ ngẩn, nhưng tôi không đủ khả năng để làm hỏng nó.

Tôi có một loạt các thư mục như vậy:

/ người dùng / tôi / foo / oops1

/ người dùng / tôi / foo / oops2

/ người dùng / tôi / foo / oops3

/ người dùng / tôi / foo / oops4

/ người dùng / tôi / foo / bar

Thật không may, chúng không được đặt tên thống nhất như thế và có hàng trăm thư mục rất tiếc.

Tôi dự định sao chép tất cả các thư mục oops vào thanh. Có cách nào dễ dàng để di chuyển tất cả các thư mục oops vào thanh không dẫn đến một số vấn đề di chuyển đệ quy không?

Phải mất vài giờ để sao chép các tập tin. Tôi hy vọng rằng việc di chuyển sẽ nhanh hơn nhiều.

Đây là trên một máy chủ linux redhat. Tôi chỉ có quyền truy cập ssh.

Tôi nghĩ nếu tôi làm

cd foo
mv * bar

sẽ có một vấn đề


Vậy thì chúng được đặt tên là gì? Bạn có muốn di chuyển mọi thứ trong foo ngoài thanh vào thanh không?
cpast

Chính xác. Họ có nhiều tên khác nhau.
jgritty

Câu trả lời:


3

Không may, Câu trả lời của Matt Câu trả lời của Nicole cả hai đều thể hiện phong cách xấu và sẽ phá vỡ nếu bất kỳ thư mục nào thậm chí chứa một ký tự khoảng trắng, ký tự toàn cầu (như * ) hoặc một dòng mới. Đang chạy for item in $(ls …) là một sai lầm lớn mà người ta có thể mắc phải vì nó sẽ cắn chúng sớm hay muộn, và lặp đi lặp lại qua tên tệp, không xuất ra chúng đúng cách có thể gây ra đủ loại rắc rối.

Không bao giờ phân tích đầu ra của ls.

Có một công cụ trong Linux để tìm các tệp phù hợp với các tiêu chí nhất định và được gọi là find:

find . -mindepth 1 -maxdepth 1 \
-type d ! -regex ".\/bar$" \
-exec mv '{}' ./bar/ \;

Điều này sẽ di chuyển bất kỳ thư mục trong thư mục làm việc hiện tại không được gọi là bar vào ./bar/. Nó sẽ hoạt động ngay cả khi tên thư mục chứa khoảng trắng, ký tự toàn cầu hoặc dòng mới.

Biểu thức chính quy .\/bar$ sẽ chỉ khớp với thư mục được gọi ./barvà nó bị phủ nhận bởi !.


Nhưng cái này cũng rất chậm vì nó chạy mv một lần cho mỗi tập tin. Và với rất nhiều điều khoản, nó thể hiện rất nhiều cơ hội để phạm sai lầm. bash cần và thiếu một cơ sở thay thế tốt hơn có thể xử lý tên tập tin với không gian.
Nicole Hamilton

Vâng, nó chạy mv một lần cho mỗi thư mục , không tập tin. Tôi tin với \+ nó sẽ chạy nhanh hơn và di chuyển tất cả các thư mục trong một lệnh, mặc dù tôi không biết liệu điều đó có gây ra sự tăng tốc lớn hay không. Tôi đồng ý với bạn rằng điều này sẽ dễ dàng hơn, bởi vì khi xử lý các tệp trong Bash, cách đơn giản nhất để thực hiện là không bao giờ Cách chính xác, không may. Tôi chỉ cảm thấy cần phải có một câu trả lời sẽ hoạt động trong mọi trường hợp.
slhck

May mắn thay, không có tệp nào có * hoặc dung lượng, nhưng điều này có vẻ như là một câu trả lời tốt hơn nói chung.
jgritty

6

Những gì bạn đang đề xuất là hoàn toàn chính xác. mv là đủ thông minh và sẽ nói điều này:

mv: cannot move `bar' to a subdirectory of itself, `bar/bar'

Tuy nhiên, tất cả các thư mục oopsx của bạn sẽ ở trong thanh.


3

Vâng, bạn đúng, đó sẽ là một vấn đề bởi vì * cũng sẽ phù hợp bar; bạn không thể mv thư mục vào chính nó.

Cách thức kỹ thuật là sử dụng thay thế lệnh và một vòng lặp để mv chỉ những thứ không bar. Ví dụ: trong bash, bạn có thể viết một cái gì đó như thế này, nhưng lưu ý rằng nó sẽ thất bại nếu nó chạm vào một tên có chứa khoảng trắng (vì thay thế lệnh sẽ phá vỡ mọi thứ thành các từ tại khoảng trắng.)

mv $(for i in *; do if [ $i != "bar" ]; then echo $i; fi; done) bar

Nhưng thành thật mà nói, tôi lười biếng. tôi sẽ mv tránh ra mv tất cả mọi thứ vào nó, sau đó di chuyển nó trở lại. Bạn chỉ di chuyển các liên kết hệ thống tệp, không phải nội dung tệp, vì vậy nó rất nhanh. Điều này cũng có lợi thế làm việc nếu bạn có tên với khoảng trắng.

cd foo
mv bar ../bar.save
mv * ../bar.save
mv ../bar.save bar

Tập lệnh của bạn không hoạt động nếu bất kỳ thư mục nào chứa khoảng trắng, ký tự toàn cầu hoặc dòng mới. Ví dụ, một thư mục được gọi là "foo baz" sẽ xuất hiện như mv foo baz barvà sau đó thất bại.
slhck

Vâng, vâng, tôi nhận thấy bạn luôn chỉ ra điều đó. Bạn phải có cái đó trên một phím macro. Nhưng (a) nếu bạn có khoảng trắng trong tên, bạn có thể biết rằng, (b) đây là một vấn đề với bash cái đó cần được sửa Vỏ C ), (c) đây là một lý do tốt để thực hiện theo cách thứ hai, đó là những gì tôi thực sự khuyên dùng.
Nicole Hamilton

Có lẽ có hàng trăm tập lệnh bash trên Super User một mình cho thấy những khiếm khuyết tầm thường này. Đây là một trang web nơi chúng ta nên học hỏi mọi người cách đạt được điều gì đó và thích ứng với nhu cầu của họ. Từ kinh nghiệm của OP tôi sẽ không nói rằng họ biết có một không gian ở nơi đầu tiên là một vấn đề. Ít nhất bạn nên đề cập rõ ràng những giả định như vậy trong câu trả lời của bạn (sau đó tôi cũng sẽ xóa downvote). Vì vậy, có lẽ bạn có thể chỉnh sửa bài viết của bạn để làm rõ điều đó. Ngoài ra, nó không phải là vấn đề của vỏ mỗi gia nhập , đó chỉ là một vấn đề khi sử dụng sai phương pháp.
slhck

Tôi cũng đã nói chuyện với người dùng dày dạn trên Unix & amp; Linux , trong đó chính sách về các tập lệnh bash "bị hỏng" là như nhau. Chỉnh sửa để cải thiện hoặc downvote / bình luận để chỉ ra thiếu sót. Làm ơn đừng mang nó theo cá nhân cái đó nhiều người dùng ở đây đăng câu trả lời với shell script. Tôi chỉ tình cờ nhận thấy nó.
slhck

1
Trong khi sự thật là * sẽ phù hợp bar, nó là không phải một vấn đề vì 'mv' / kernel đủ thông minh để phát hiện trường hợp này. Vì vậy, thay vì nói rằng đó là một vấn đề, đó là một cách tốt để làm điều đó (trừ khi bạn muốn lọc ra các thư mục nhất định, nhưng đó là một câu hỏi khác)
JvO

1

Nếu làm cho bạn cảm thấy an toàn hơn, bạn có thể làm điều này trong BASH:

for item in `ls -d | grep -v "^bar$"`; do mv $item bar; done;

2
Điều gì về vô tình phù hợp với barf, barfly hoặc vỏ cây? Sử dụng grep -v '^bar$' để chỉ khớp với "thanh".
Perleone

1
Đồng ý. Tốt hơn với "^ bar $". Cảm ơn đã chú ý. Tôi đã cập nhật câu trả lời.
Matt

1
Đang chạy ls -d chỉ cung cấp cho bạn ., thư mục làm việc hiện tại. Bạn có chắc chắn điều này hoạt động? Bạn đã thử lệnh chưa? Xem: Làm thế nào để liệt kê các thư mục bằng cách sử dụng các lệnh bash? - hơn nữa tập lệnh này sẽ thất bại nếu bất kỳ thư mục nào chứa ký tự khoảng trắng, dòng mới hoặc ký tự trong tên của chúng.
slhck

-1: Như được chỉ ra bởi @slhck, câu trả lời này không hoạt động. Và @Perleone Câu trả lời là tốt hơn.
Adrian Pronk

-1

cd vào foo

mv -t bar oops[[:digit:]]

của tổng quát hơn

mv -t bar oops*

haha xin lỗi vì lỗi đánh máy
WikiWitz

2
Họ không thực sự được gọi là oops.
jgritty
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.