• בלוג
  • תרגיל Bash - איך להזיז את כל המספרים בתיקיה

תרגיל Bash - איך להזיז את כל המספרים בתיקיה

נתונה תיקיה עם אוסף של קבצים שהשמות של כולם מתחילים במספר ואז מקף ואז שם הקובץ (דמיינו אוסף שירים בתקליט), לדוגמה:

01-hello
02-some-text
03-i-like-bash
04-zsh-is-ok-too
05-byebye

אם נמחק את אחד הקבצים בתיקיה יהיה לנו "דילוג" בכל שאר המספרים, לדוגמה אם אני מוחק את הקובץ השני אני נשאר רק עם:

01-hello
03-i-like-bash
04-zsh-is-ok-too
05-byebye

כתבו סקריפט Bash שמתקן את הדילוג.

1. פיתרון 1 - אפשר להזיז את המספרים של כל הקבצים

דרך ראשונה תהיה לרוץ על כל הקבצים ולהוריד לכל אחד את המספר ב-1. ב Bash זה נראה ככה ויש כמה טריקים:

#!/bin/bash

for f in [0-9][0-9]*
do
  number=${f%%-*}
  number=${number#0}
  (( number < 2 )) && continue

  mv "$f" $(printf "%02d-${f#*-}" $((number - 1)))
done

שתי הפקודות הראשונות בלולאה חותכות מהמשתנה f את כל מה שבא אחרי המקף הראשון, ואחרי זה מוחקות את האפס שבהתחלה, כך שאנחנו נשארים רק עם המספר ללא הריפוד.

הפקודה הבאה היא תנאי מקוצר, אפשר לקרוא אותה בתור "אם number קטן מ-2 המשך לאיטרציה הבאה". כמובן שאת המספר 2 צריך להחליף במספר הקובץ שמוחקים.

והפקודה השלישית היא המורכבת ביותר, היא משתמשת בדולר-ואז-פעמיים-סוגריים כדי להוריד אחד מ number, ואת התוצאה מעבירה בתור פרמטר שני לפונקציה printf שמרפדת אותו ב-0 ומצמידה אליו את שם הקובץ בלי המספר שבהתחלה. וכן, הכתיב המצחיק של ה f עם הסולמית אומר למחוק מהמשתנה f את כל מה שבא לפני המקף הראשון.

2. פיתרון 2 - אפשר למספר הכל מחדש

גישה קצת יותר גמישה פשוט תמספר מחדש את כל הקבצים, כי בינינו יכול להיות שמחקו יותר מקובץ אחד ועדיף להמשיך לעבוד גם במצבים מוזרים כאלה. הרעיון הוא כזה:

#!/bin/bash -e

number=1

for f in [0-9][0-9]*
do
  newname=$(printf "%02d-${f#*-}" $number)
  (( number++ ))

  [[ "$f" == "$newname" ]] && continue

  mv "$f" "$newname"

done

אנחנו לוקחים את רשימת כל הקבצים בתיקיה ומתבססים על זה שה glob מחזיר את הקבצים לפי סדר מילוני. עכשיו אפשר לרוץ בלולאה על הקבצים ולכל אחד לתת שם חדש שמתאים לאינדקס שלו. הפעולה number++ בתוך סוגריים עגולים כפולים מעלה ב-1 את המשתנה, וה printf אחראי על יצירת השם החדש. הפעם ההחלטה לדלג לקובץ הבא תלויה בשם הקובץ החדש והאם השמות זהים. בעיקרון אפשר לוותר על הבדיקה כי mv ממילא ייכשל אם שמות הקבצים זהים אבל אני מעדיף לא להכשיל תוכניות באמצע סקריפט.

3. עכשיו אתם

  1. בפיתרון הראשון הורדתי את האפס שריפד את המספר שלפני שם הקובץ (שורה שניה בתוך הלולאה). מה יקרה אם נוותר על שורה זאת ונשאיר את האפס?

  2. בפיתרון הראשון השתמשתי בסוגריים עגולים כפולים בשביל התנאי המקוצר אבל בפיתרון השני בסוגריים מרובעים כפולים. מה ההבדל בין השניים? איך היה נשבר קוד הפיתרון השני אם הייתי כותב בו סוגריים עגולים במקום מרובעים?

  3. יש לכם רעיונות נוספים לפיתרון? מוזמנים לשתף בתגובות.