เชลล์สคริปต์การวนลูปผ่านโฟลเดอร์


1

ฉันมีโฟลเดอร์ย่อยจำนวนมากบน Mac ของฉันพร้อมไฟล์ csv จำนวนสุ่มในแต่ละไฟล์ สิ่งที่ฉันต้องการทำคือรวมไฟล์เหล่านี้เป็นไฟล์เดียวสำหรับแต่ละไดเรกทอรี

จนถึงตอนนี้ฉันรู้ว่าฉันสามารถรวมไฟล์เหล่านี้ด้วยcat * > mergedfile.csvแต่ฉันมีปัญหาซ้ำผ่านโฟลเดอร์ทั้งหมด ฉันพยายามรวมสิ่งต่าง ๆ เข้าด้วยกัน แต่ฉันไม่สามารถทำให้สิ่งนี้เป็นสิ่งที่ฉันต้องการได้อย่างแน่นอน

มีความคิดเกี่ยวกับวิธีที่ดีที่สุดในการทำเช่นนี้?

for DIR in ./subfolder/*
do
    cat $dir/* > merged.csv 
done

1
$DIRและ$dirไม่เหมือนกัน
choroba

คำตอบ:


4

ด้วยfindคุณซ้ำสามารถแสดงรายชื่อไฟล์ทั้งหมดที่ตรงกับเกณฑ์บางอย่างเช่นชื่อไฟล์

for file in $(find . -type f -name "*.csv"); do cat "$file" >> /path/to/output.csv; done

เมื่อเสร็จแล้วfind . -name "*.csv"จะค้นหาไฟล์ CSV ทั้งหมดจากโฟลเดอร์ปัจจุบันที่คุณอยู่ ( .) และลูปจะวนซ้ำในรายการนั้นต่อท้ายทุกสิ่งลงในoutput.csvไฟล์

แต่:ชื่อไฟล์ที่มีช่องว่าง, ตัวอักษรกลมและขึ้นบรรทัดใหม่อาจเป็นเรื่องยุ่งยากที่นี่ โซลูชันที่ปลอดภัยกว่าคือการใช้execสำหรับคำสั่ง find

find . -name "*.txt" -exec cat '{}' >> /path/to/output.csv ';'

ที่นี่'{}'จะถูกแทนที่ด้วยค้นหาด้วยชื่อไฟล์ สำหรับ Q & A ยาวเกี่ยวกับสาเหตุที่นี้และวิธีการที่จะหลีกเลี่ยงปัญหาที่สามารถพบได้ที่นี่

ตอนนี้ถ้าคุณต้องการสร้างไฟล์ CSV หนึ่งไฟล์สำหรับแต่ละไดเรกทอรี - ขออภัยไม่เคยเห็นมาก่อน - ฉันอาจทำสิ่งนี้:

for dir in $(find . -type d); do find $dir -maxdepth 1 -name "*.csv" -exec cat {} >> "$dir/out" ';'; mv "$dir/out" "$dir/merged.csv"; done

แม้ว่าวิธีการแก้ปัญหาของ Franck ด้านล่างอาจมีประสิทธิภาพมากกว่า


ของหลักสูตรให้ความสนใจกับความแตกต่างระหว่างและ> >>อดีตจะตัดไฟล์ให้มีความยาวเป็นศูนย์เสมอก่อนที่จะเขียนลงไปในขณะที่ไฟล์หลังจะต่อท้ายไฟล์

เหตุผลที่ใช้cat *.csv > merged.csvงานได้ - และทำไมในวงของคุณมันไม่ทำงาน - คือเชลล์จะขยายสัญลักษณ์แทนก่อนดังนั้นโดยทั่วไปจึงเห็น:

cat file1.csv file2.csv file3.csv > merged.csv

... ซึ่งแน่นอนว่าจะไม่เขียนทับอะไรเลย


1

เข้าไปในโฟลเดอร์พาเรนต์:

for dir in $(find . -type d); do
  cd $dir
  [[ $(ls *.csv|wc -l) -eq 0 ]] 2> /dev/null || { print "$dir.csv created";
                                                  cat *.csv > $dir.csv; }
  cd - > /dev/null
done

1

สมมติว่าทุบตี 4+ (ตรวจสอบด้วยbash --version) คุณสามารถเปิดใช้งาน globstar ด้วยshopt -s globstarและวนซ้ำผ่านไดเรกทอรีทั้งหมด (และเฉพาะไดเรกทอรี - ไฟล์ต่อท้าย/ออกกฎไฟล์) ซ้ำด้วย**/

for f in **/; do cat "$f"/*.csv > "$f"/merged.csv; done

ถ้าคุณอย่างแท้จริงต้องการที่จะใช้ทุกไฟล์ในไดเรกทอรีมากกว่าเพียง แต่ผู้ที่ลงท้ายด้วย.csvแล้ว

for f in **/; do cat "$f"/* > "$f"/merged.csv; done

ถ้าคุณต้องการที่จะลงไปในระดับเดียวแทนที่จะเป็น recursive อย่างเต็มที่แล้วใช้มากกว่า*/**/

ความผิดพลาดที่สำคัญในสคริปต์ OP (นอกเหนือจากการลืมทุบตีว่าเป็นกรณีที่มีความอ่อนไหว) เป็นความพยายามที่จะเขียนเนื้อหาของทุกไฟล์ที่เป็นหนึ่ง.csvไฟล์และไม่ได้อยู่ในลักษณะที่เป็นซ้ำของวงแต่ละคนจะมากกว่า - เขียนสุดท้าย

หากคุณต้องการที่จะเชื่อมทุก.csvไฟล์ซ้ำเป็นไฟล์เดียวคุณอีกครั้งอาจจะใช้ GLOBSTAR

for f in **/*.csv; do cat "$f" > merged_all.csv
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.