טיפ Bash - בואו נבטל תיקיות אמצע עם find

15/09/2019

הפקודה find מסתירה לא מעט קלפים בשרוול. הנה אחד שמצאתי מועיל לפני כמה ימים שאולי יעזור גם לכם.

קיבלתי עץ תיקיות שכלל הרבה תיקיות אמצע ריקות, דמיינו משהו שנראה כך:

.
└── a
    └── b
        ├── c
        │   └── d
        │       └── e
        │           ├── one.txt
        │           ├── three.txt
        │           └── two.txt
        ├── f
        │   └── g
        │       ├── five.txt
        │       ├── four.txt
        │       └── six.txt
        └── y
            └── seven.txt

ורציתי להיפטר מתיקיות האמצע ולהגיע למבנה כזה:

.
└── a
    ├── c
    │   ├── one.txt
    │   ├── three.txt
    │   └── two.txt
    ├── f
    │   ├── five.txt
    │   ├── four.txt
    │   └── six.txt
    └── y
        └── seven.txt

כלומר ביטול התיקיות b, d, e ו g.

דרך קלה לבטל את תיקיות האמצע תהיה להשתמש ב find:

  1. נמצא את התיקיה העמוקה ביותר שיש להורה שלה רק ילד אחד (כלומר שהיא בן יחיד בעץ התיקיות).

  2. נעביר את כל הקבצים שבה להורה שלה, ואז נמחק את התיקיה.

  3. נחזור על התהליך עד שנסיים לרוץ על כל עץ התיקיות.

המתגים הרלוונטים של find הם לכן:

  1. המתג -d שיגרום ל find להתחיל מהתיקיה העמוקה ביותר ולרוץ כלפי חוץ.

  2. המתג -type d שיגרום ל find לרוץ רק על תיקיות.

  3. המתג -exec שיאפשר לנו להריץ קוד במהלך החיפוש.

ופקודה ה find שחיברה את הכל נראתה כך:

$ find -d . -type d -exec bash -c '[[ $(ls {}/.. | wc -l | tr -d " ") == 1 ]] && (mv {}/* {}/..; rmdir {})' \;

בעיה יחידה שעשויה להתעורר היא שהתיקיה העליונה ביותר בעץ היא בן יחיד ולכן תבוטל. בשביל לעקוף את זה יצרתי תיקיה זמנית ברמה העליונה ביותר בעץ (ליד a) ואחרי ה find מחקתי גם אותה.

נ.ב. כן כנראה שאפשר לכתוב סקריפטים רציניים בשפות רציניות כדי להגיע לאותה תוצאה, ואם זה משהו שאתם עושים לעתים קרובות סיכוי טוב שגם כדאי לכתוב כאלה סקריפטים. בשביל משימות חד-פעמיות אני חושב ששליטה טובה ב find (ובכלל בכלי העבודה של יוניקס) יכולה לתת Productivity Boost משמעותי ושווה את ההשקעה בלימוד.