cd ลงในไดเร็กทอรีทั้งหมดรันคำสั่งบนไฟล์ในไดเร็กทอรีนั้นและกลับไปยังไดเร็กทอรีปัจจุบันก่อนหน้า


41

ฉันกำลังพยายามเขียนสคริปต์ที่จะทำงานในไดเรกทอรีที่กำหนดพร้อมกับไดเรกทอรีย่อยระดับเดียวหลายรายการ สคริปต์จะ cd ลงในแต่ละไดเรกทอรีย่อยดำเนินการคำสั่งในไฟล์ในไดเรกทอรีและ cd out เพื่อดำเนินการต่อไปยังไดเรกทอรีถัดไป วิธีที่ดีที่สุดในการทำเช่นนี้คืออะไร?


1
เมื่อได้รับข้อมูลในระดับปัจจุบันฉันไม่เห็นความเกี่ยวข้องyoutube-dlเลย
HalosGhost

คำตอบ:


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

12
ดังนั้นเนื่องจากผู้ตอบไม่ต้องอธิบายอะไรเลยฉันจะลองดู for d in ./*/เริ่มห่วงว่าร้านค้าในทุกรายการ./*/(รายชื่อของไฟล์ / โฟลเดอร์ในกรณีนี้) $dในตัวแปร do (cd "$d" && somecommand);เริ่มเนื้อความของลูป ภายในร่างกายจะเริ่มsubshellและรันคำสั่งcdและ somecommandเนื่องจากมันเป็นเปลือกลูกเปลือกหลัก (เปลือกที่คุณใช้คำสั่งนี้) จะคงไว้ซึ่ง CWD และตัวแปรสภาพแวดล้อมอื่น ๆ doneเพียงแค่ปิดร่างกายห่วง
Qix

วิธีนี้สำหรับไดเรกทอรีย่อยของไดเรกทอรี: for d in ./*/ ; do (cd "$d" && ls); doneจะไม่ทำงาน แต่for d in ./*/ ; do (cd "$d" && for d in ./*/ ; do (cd "$d" && ls); done ); doneจะได้ผล - ใช้ ls เป็นคำสั่งในตัวอย่างนี้
Michael Dimmitt

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

15

วิธีที่ดีที่สุดคือไม่ใช้cdเลย:

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

execdirเป็นเหมือนexecแต่ไดเรกทอรีทำงานแตกต่างกัน:

   -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.

มันไม่ใช่ POSIX


สิ่งนี้ใช้ได้กับนามแฝงหรือไม่ ฉันมีหนึ่งไฟล์ที่จะดาวน์โหลด แต่มันไม่รู้จักเมื่อฉันพิมพ์ในค้นหา * /. link -type f -execdir md $ (cat .link) {} \;
Something Jones

@SomethingJones no findดำเนินการคำสั่งเหล่านั้นดังนั้นจึงไม่ทราบถึงนามแฝง ไดเรคทอรี่คืออะไรmdและคือ.linkอะไร?
muru

.link เป็นไฟล์ข้อความที่มี URL ที่จำเป็นต้องดาวน์โหลด md เป็นชื่อแทนเพื่อ wget โดยตั้งค่าสถานะเป็นพวง มีวิธีที่จะทำให้ทราบถึงนามแฝงหรือไม่?
Something Jones

@SomethingJones สำหรับกรณีการใช้งานของคุณโดยเฉพาะในbash: find . -type f -iname '*.link' -execdir ${BASH_ALIASES[md]} -i {} \;คุณไม่จำเป็นต้องที่จะทำcatด้วยwgetซึ่งมี-iธงสำหรับการอ่านใน URL จากไฟล์ นอกจากนี้ยังค่อนข้างแตกต่างจากคำถามเดิมของคุณ (เนื่องจากคุณสนใจเฉพาะไฟล์ที่มีชื่อ.linkและไม่ใช่ไฟล์อื่น ๆ ที่อาจมีอยู่)
muru

คุณรู้วิธีการทำกับ zsh หรือไม่ ฉันลองสิ่งที่คุณให้ฉันและฉันได้รับข้อผิดพลาด "การแทนที่ไม่ถูกต้อง" นอกจากนี้ฉันจะแยกเนื้อหาของไฟล์. link ได้อย่างไร ฉันรู้ว่าฉันไม่ต้องการมันในกรณีนี้ แต่ฉันคิดว่าฉันจะทำในไม่ช้า
Something Jones

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

คำสั่งดังกล่าวไม่จำเป็นต้องทำ subshells ใด ๆ - มันเป็นเพียงแค่ติดตามความคืบหน้าในเปลือกปัจจุบันโดยสลับกันและ$OLDPWD $PWDเมื่อคุณcd -เชลล์แลกเปลี่ยนค่าของตัวแปรทั้งสองนี้โดยทั่วไปมันจะเปลี่ยนไดเรกทอรี นอกจากนี้ยังพิมพ์ชื่อสำหรับแต่ละไดเรกทอรีตามที่ทำงานไปยัง stderr

ฉันเพิ่งดูครั้งที่สองและตัดสินใจว่าฉันจะทำงานได้ดีขึ้นด้วยการจัดการข้อผิดพลาด มันจะข้าม dir ที่มันไม่สามารถcd- และcdจะพิมพ์ข้อความเกี่ยวกับสาเหตุของ stderr - และมันจะbreakมีรหัสทางออกที่ไม่เป็นศูนย์หากคุณcommandดำเนินการไม่สำเร็จหรือหากการรันcommandมีผลต่อความสามารถในการกลับไปยังไดเรกทอรีต้นฉบับของคุณ $OLDPWD- ในกรณีดังกล่าวมันจะใช้cd -นามสกุล - และเขียนชื่อไดเรกทอรีการทำงานปัจจุบันที่เป็นผลลัพธ์ไปยัง stderr


โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.