cd vào tất cả các thư mục, thực thi lệnh trên các tệp trong thư mục đó và quay lại thư mục hiện tại trước đó


41

Tôi đang cố gắng viết một tập lệnh sẽ được chạy trong một thư mục nhất định với nhiều thư mục con cấp đơn. Kịch bản lệnh sẽ cd vào từng thư mục con, thực thi một lệnh trên các tệp trong thư mục và cd ra để tiếp tục vào thư mục tiếp theo. Cách tốt nhất để làm việc này là gì?


1
Với mức độ thông tin hiện tại được đưa ra, tôi thấy không liên quan đến youtube-dl.
HalosGhost

Câu trả lời:


83
for d in ./*/ ; do (cd "$d" && somecommand); done

12
Vì người trả lời đã bỏ qua bất kỳ lời giải thích nào, tôi sẽ thử. for d in ./*/bắt đầu một vòng lặp lưu trữ mọi mục trong ./*/(một danh sách các tệp / thư mục, trong trường hợp này) trong một biến $d. do (cd "$d" && somecommand);bắt đầu cơ thể của vòng lặp. Bên trong cơ thể, nó khởi động một lớp con và chạy các lệnh cdsomecommand. Vì nó là shell con, shell cha (shell mà bạn đang chạy lệnh này) giữ lại CWD và các biến môi trường khác. donechỉ đơn giản là đóng thân vòng lặp.
Qix

phương thức này cho các thư mục con của thư mục : for d in ./*/ ; do (cd "$d" && ls); done, sẽ không hoạt động. nhưng, for d in ./*/ ; do (cd "$d" && for d in ./*/ ; do (cd "$d" && ls); done ); donesẽ làm việc -sử dụng ls như lệnh trong ví dụ này.
Michael Dimmitt

-bash: cd: ./*/: No such file or directory
S. Tarık Çetin

15

Cách tốt nhất là không sử dụng cdtất cả:

find some/dir -type f -execdir somecommand {} \;

execdirlà như thế exec, nhưng thư mục làm việc là khác nhau:

   -execdir command {} [;|+]
          Like   -exec,   but  the  specified  command  is  run  from  the
          subdirectory containing the matched file, which is not  normally
          the  directory  in  which  you  started  find.  This a much more
          secure  method  for  invoking  commands,  as  it   avoids   race
          conditions  during resolution of the paths to the matched files.

Nó không phải là POSIX.


Điều này có làm việc với bí danh? Tôi có một tệp để tải xuống một số tệp nhất định nhưng nó không nhận ra nó khi tôi gõ find * /. Link -type f -execdir md $ (cat .link) {} \;
Một cái gì đó Jones

@S SomethingJones no, findthực thi các lệnh đó, vì vậy nó sẽ không nhận ra bí danh. Một mdvà là .linkmột thư mục là gì?
muru

.link là một tệp văn bản có URL cần tải xuống. md là một bí danh để wget với một loạt các cờ được thiết lập. Có cách nào để làm cho nó nhận biết bí danh?
Một cái gì đó Jones

@SomethingJones Đối với trường hợp sử dụng cụ thể của bạn, trong bash: find . -type f -iname '*.link' -execdir ${BASH_ALIASES[md]} -i {} \;Bạn không cần phải làm catvới wget, trong đó có một -ilá cờ để đọc trong một URL từ một tập tin. Ngoài ra, điều này hơi khác so với câu hỏi ban đầu của bạn (vì bạn dường như chỉ quan tâm đến các tệp có tên .linkvà không phải bất kỳ tệp nào khác có thể có mặt).
muru

Bạn có biết làm thế nào để làm điều đó với zsh? Tôi đã thử những gì bạn đã cho tôi và nhận được một lỗi "Thay thế xấu". Ngoài ra, làm cách nào tôi có thể trích xuất nội dung của tệp .link? Tôi biết tôi không cần nó trong trường hợp này nhưng tôi tưởng tượng mình sẽ sớm thôi.
Một cái gì đó Jones

2
cd -P .
for dir in ./*/
do cd -P "$dir" ||continue
   printf %s\\n "$PWD" >&2
   command && cd "$OLDPWD" || 
! break; done || ! cd - >&2

Lệnh trên không cần thực hiện bất kỳ chuỗi con nào - nó chỉ theo dõi tiến trình của nó trong trình bao hiện tại bằng cách xen kẽ $OLDPWD$PWD. Khi bạn cd -các shell trao đổi giá trị của hai biến này, về cơ bản, vì nó thay đổi thư mục. Nó cũng in tên cho mỗi thư mục khi nó hoạt động ở đó để stderr.

Tôi chỉ có một cái nhìn thứ hai về nó và quyết định tôi có thể làm tốt hơn với việc xử lý lỗi. Nó sẽ bỏ qua một thư mục mà nó không thể cd- và cdsẽ in một thông báo về lý do tại sao để stderr - và nó sẽ breakcó mã thoát không bằng 0 nếu bạn commandkhông thực thi thành công hoặc nếu chạy commandbằng cách nào đó ảnh hưởng đến khả năng quay lại thư mục gốc của bạn - $OLDPWD. Trong trường hợp đó, nó cũng thực hiện cd -lần cuối - và ghi tên thư mục làm việc hiện tại vào stderr.


1
for D in ./*; do
    if [ -d "$D" ]; then
        cd "$D"
        run_something
        cd ..
    fi
done
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.