Cấu trúc thư mục làm phẳng


8

Tôi có cấu trúc thư mục này:

├── foo1
   ├── bar1.txt
   └── bar2.txt
├── foo2
   ├── bar3.txt
   └── bar4 with a space.txt
└── foo3
    └── qux1
        ├── bar5.txt
        └── bar6.txt

rằng tôi muốn làm phẳng điều này, với một dấu gạch dưới giữa mỗi cấp độ thư mục:

├── foo1_bar1.txt
├── foo1_bar2.txt
├── foo2_bar3.txt
├── foo2_bar4 with a space.txt
├── foo3_qux1.bar6.txt
└── foo3_qux1_bar5.txt

Tôi đã nhìn xung quanh và tôi không tìm thấy bất kỳ giải pháp nào hoạt động, chủ yếu là tôi nghĩ bởi vì vấn đề của tôi có hai đặc điểm: có thể có nhiều hơn một cấp thư mục bên trong thư mục gốc và cũng vì một số tệp có thể có khoảng trắng.

Bất kỳ ý tưởng làm thế nào để thực hiện điều này trong bash? Cảm ơn!

Chỉnh sửa : Chạy gleen jackman đề xuất câu trả lời Tôi nhận được điều này:

nhập mô tả hình ảnh ở đây

Có hai dấu gạch dưới cho thư mục cấp đầu tiên. Bất kỳ ý tưởng làm thế nào để tránh điều này hoặc chỉ đổi tên nó để chỉ là một gạch dưới? Cảm ơn.

Câu trả lời:


15
find */ -type f -exec bash -c 'file=${1#./}; echo mv "$file" "${file//\//_}"' _ '{}' \;

loại bỏ echonếu bạn hài lòng, nó hoạt động. Đừng lo lắng rằng các lệnh echo không hiển thị dấu ngoặc kép, tập lệnh sẽ xử lý các tệp có khoảng trắng đúng cách.

Nếu bạn muốn xóa các thư mục con trống bây giờ:

find */ -depth -type d -exec echo rmdir '{}' \; 

Chào. Thật tuyệt vời! Cảm ơn. Điều đó đã lừa gần như hoàn toàn. Tôi chỉ gặp một vấn đề nhỏ, đó là tôi đang gặp phải foo1__qux1_bar5.txt, hai dấu gạch dưới ở cấp thư mục đầu tiên. Đã thử gây rối với dòng bash của bạn nhưng dường như không có gì để làm việc. Có lẽ tôi cần thêm một cái gì đó?
nunos

@nunos, tôi không thể tái tạo rằng hành vi
glenn jackman

Có thật không? Kỳ dị. Tôi chỉ cập nhật câu trả lời của tôi với một số thông tin thêm. Bạn có thể vui lòng xem qua? Cảm ơn.
nunos

1
Huh. OK, thay đổi "${file//\//_}"thành "${file//+(/)/_, và nếu đây là một kịch bản,shopt -s extglob
glenn jackman

Tôi đã có vấn đề với hai dấu gạch dưới là tốt. Thật không may, thay đổi lệnh như bạn đề nghị không làm việc cho tôi. Tuy nhiên, tôi đã tìm thấy câu trả lời này trên AskDifferent: apple.stackexchange.com/a/254224/122152 Theo câu trả lời, macOS có thể đang sử dụng BSD find. Một cách giải quyết có thể là sử dụng findutils. Nó có thể được cài đặt bằng homebrew brew install findutilsvà sau đó sử dụng gfindthay vì find. Điều này làm việc cho tôi.
intagli

5

Sử dụng đổi tên của perl:

find . -depth -type f -exec rename 's@(?<!\.)/@_@g' -- {} \;

ĐẦU RA

$ find -type f
./foo2_bar4 whit a space.txt
./foo3_qux1_bar6.txt
./foo2_bar3.txt
./foo3_qux1_bar5.txt
./foo1_bar2.txt
./foo1_bar1.txt

GHI CHÚ

  • Tôi sử dụng cái nhìn tiêu cực phía sau (?<!\.) để không chạm vào cái đầu tiên./
  • Tôi giữ các thư mục trống, cảm thấy tự do:

    find . -depth -type d -exec rm {} \;

cảnh báo Có những công cụ khác có cùng tên có thể hoặc không thể làm điều này, vì vậy hãy cẩn thận.

Nếu bạn chạy lệnh sau ( GNU)

$ file "$(readlink -f "$(type -p rename)")"

và bạn có một kết quả như

.../rename: Perl script, ASCII text executable

và không chứa:

ELF

thì đây có vẻ là công cụ phù hợp =)

Nếu không, để làm cho nó mặc định (thường là trường hợp) trên Debianvà phái sinh như Ubuntu:

$ sudo update-alternatives --set rename /path/to/rename

(thay thế /path/to/renamecho đường dẫn của perl's renamelệnh của bạn .


Nếu bạn không có lệnh này, hãy tìm kiếm trình quản lý gói của bạn để cài đặt hoặc thực hiện thủ công


Cuối cùng nhưng không kém phần quan trọng, công cụ này ban đầu được viết bởi Larry Wall, cha của Perl.


... -type d -exec rmdir ...?
JJoao

Tôi dường như không đổi tên có sẵn .. Làm thế nào chính xác tôi có thể có được nó và điều này thường có sẵn trong một hệ thống UNIX? Cảm ơn.
nunos

@nunos Đó là một kịch bản Perl. Nó có sẵn dưới tên perl-renametrong Arch Linux và prenametrong các hệ thống dựa trên Debian.
muru

Đã thêm renamegiải thích
Gilles Quenot

1

với pax...

pax -Xrwls '|/|_|g' */ "$PWD"

Điều đó sẽ tạo ra một liên kết cứng trong thư mục hiện tại đến tất cả các tệp trong thư mục con của nó với một _thay thế cho /. Sau đó, bạn có thể kiểm tra kết quả và xóa tất cả các thư mục con bằng ...

rm -rf */

... Một khi bạn đã xác minh kết quả theo ý thích của bạn.


0

Bạn có thể thử với lệnh dưới đây.

$ find -type f -exec bash -c 'mv $0 $(echo $0|sed "s/\//_/2")' {} \;

Lệnh trên sẽ di chuyển các tập tin và thư mục sẽ vẫn còn có thể được gỡ bỏ sau đó.

$ ls
foo1_bar1.txt  foo1_bar2.txt  foo2_bar3.txt  foo2_bar4.txt  foo3_bar5.txt  foo3_bar6.txt
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.