Đi qua tất cả các thư mục con trong và làm một cái gì đó trong tập lệnh shell Unix


17

Tôi muốn tập lệnh shell của tôi truy cập tất cả các thư mục con trong một thư mục chính. Làm một cái gì đó trong các thư mục, gửi đầu ra đến một tập tin spool và chuyển sang thư mục tiếp theo. Xem xét Main Dir = / tmp Sub Dir = ABCD (Bốn thư mục con)


2
OK, xin vui lòng cho chúng tôi xem kịch bản của bạn cho đến nay. Phần nào của nó đang mang lại cho bạn rắc rối?
terdon

Câu trả lời:


22

Sử dụng một forvòng lặp:

for d in $(find /path/to/dir -maxdepth 1 -type d)
do
  #Do something, the directory is accessible with $d:
  echo $d
done >output_file

Nó chỉ tìm kiếm các thư mục con của thư mục /path/to/dir. Lưu ý rằng ví dụ đơn giản ở trên sẽ thất bại nếu tên thư mục chứa khoảng trắng hoặc ký tự đặc biệt. Một cách tiếp cận an toàn hơn là:

find /tmp -maxdepth 1 -type d -print0 |
  while IFS= read -rd '' dir; do echo "$dir"; done

Hoặc đồng bằng bash:

for d in /path/to/dir/*; do
  if [ -d "$d" ]; then
    echo "$d"
  fi
done

(lưu ý rằng trái với findđiều đó người ta cũng xem xét các liên kết tượng trưng đến các thư mục và loại trừ các liên kết ẩn)


1
ít nhất chỉ ra những hạn chế và rủi ro liên quan đến việc xử lý đầu ra findnhư thế.
Stéphane Chazelas 27/2/2015

Xin chào ... tôi đã cố chạy bên dưới vòng lặp cho d trong $ (find / backup / ASHISH -maxdepth 1 -type d) do ls -l | awk '{print $ 9}' | grep CC * _ date +"%m%d20%Y"| xargs echo echo $ d
Ashish

Xin chào ... Tôi đã thử bên dưới cho vòng lặp. for d in $ (find / backup / ASHISH -maxdepth 1 -type d) do ls -l | awk '{print $ 9}' | grep CC * _ date +"%m%d20%Y"| xargs echo echo $ d Kết quả mong đợi là ls -ltr từ tất cả thư mục con . Vòng lặp trên không hoạt động
Ashish

1

Tôi là một người bashmới hoàn toàn , nhưng là một cựu chiến binh UN * X. Mặc dù chắc chắn điều này có thể được thực hiện trong kịch bản shell Bash, nhưng ngày xưa chúng ta thường sử dụng find [-maxdepth <levels>] <start-dir> -exec <command> ;để đạt được điều này. Bạn có thể làm một man findvà chơi xung quanh, có lẽ cho đến khi ai đó cho bạn biết làm thế nào để làm điều đó bash!


Tôi rất hãnh diện rằng câu trả lời "phác thảo" của tôi ở đây đã nhận được một cuộc bỏ phiếu. Tuy nhiên, tại sao câu trả lời của @chaos dưới đây lại nhận được phiếu bầu thấp? (Là một người mới tham gia diễn đàn này, tôi không thể đăng bình luận này chống lại câu trả lời của anh ấy, chỉ chống lại câu trả lời của tôi.) Đề xuất thứ hai của anh ấy là chính xác cho một giải pháp kịch bản shell và tránh chi phí hoạt động của một findlệnh bên ngoài .
JonBrave

Thứ hai của ông là thực sự chính xác. Đầu tiên của anh ta sẽ thất bại nếu tên thư mục chứa khoảng trắng hoặc ký tự đặc biệt (ví dụ dấu gạch chéo ngược). Xem bản chỉnh sửa tôi thực hiện để trả lời cho phiên bản an toàn.
terdon

Tôi đồng ý. Đó là câu trả lời thứ hai, chỉ có vỏ của anh mà tôi đang ca ngợi.
JonBrave

Tôi biết, tôi chỉ đang giải thích về downvote (mà tôi không chọn).
terdon


1

Có vẻ như bạn muốn tên tập tin dưới mỗi thư mục con; điều đó ls -l | awkkhông đủ mạnh, vì điều gì sẽ xảy ra nếu những tên tập tin đó bao gồm khoảng trắng và / hoặc dòng mới? Những điều dưới đây findsẽ hoạt động ngay cả đối với findviệc donot tình cờ xảy ra -maxdepthvới họ:

find . ! -name . -type d -prune -exec sh -c '
   cd "$1" && \
   find "." ! -name . -prune  -type f
' {} {} \;

0

Tôi đã có giải pháp. Lệnh find dưới đây đáp ứng yêu cầu của tôi.

find . -maxdepth 1 -type d \( ! -name . \) -exec bash -c "cd '{}' && ls -l |awk '{ print $9 }' |grep `date +"%m%d%Y"`|xargs echo" \;

0

Cũng có thể sử dụng ls, grep và tr

for dir in $(ls -1FA | grep / | tr -d /); do echo $dir/something; done

ls -1FA | grep / | tr -d / | while IFS= read -r TD; do echo $TD/something; done

du / sed cũng có thể được sử dụng làm công cụ chọn nếu ls của bạn thiếu các tùy chọn trên

du --max-depth=1 | sed -e 's/^.*\.\///' | grep -v '\.$'

Điều quan trọng cần lưu ý là các ví dụ này trả về các thư mục ẩn và loại trừ các thư mục mẹ và các thư mục hiện tại


1
(1)  lsghi một tệp trên mỗi dòng ( -1tùy chọn chỉ định) theo mặc định khi đầu ra tiêu chuẩn là một đường ống (vì vậy nó không cần thiết trong câu trả lời của bạn). (2) Phân tích đầu ra của lsmột ý tưởng tồi - xem cái nàycái này . Câu trả lời đầu tiên của bạn sẽ thất bại nếu các thư mục có khoảng trắng (hoặc dòng mới) trong tên của chúng và tất cả sẽ thất bại nếu chúng có dòng mới trong tên của chúng. (3) Bạn phải luôn trích dẫn các biến shell (ví dụ "$dir":) trừ khi bạn có lý do chính đáng để không và bạn chắc chắn rằng bạn biết bạn đang làm gì.
Scott

Điểm tốt Scott. Để lại câu trả lời là, đối với nhiều hệ thống không có thư mục được đặt tên quá lớn, tôi nghĩ rằng nó có thể vẫn hữu ích cho một lần tắt.
JGurtz
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.