שאלה ב-unix

sharon1003

New member
שאלה ב-unix

שלום,
יש לי שאלה ב-UNIX.
למשל יש לי קובץ בשם 1.txt המכיל את השורות הבאות:
C001 BLA BLA
C002 FGD DTF
C002 FSR HRE
C006 DFE FEW
C006 FEH RWE
C989 FWE HWR
ויש לי גם קובץ נתונים 2.txt שמכיל את העמודה הראשונה בעמודה הראשונה (שהופיע בקובץ הקודם) עם הנתונים הבאים:
C001 ABC ABC
C002 FGH WTD
C006 FSW DSA
C989 OIP JCD
ברצוני לאחד בין שני הקבצים וליצור בכל שורת רווח בקובץ המקורי את הפלט המתאים עבורו שיילקח מהקובץ השני לפי העמודה הראשונה בעמודה הראשונה של הקובץ הראשון (אפשר להשתמש עם grep על העמודה הראשונה).
כלומר ליצור קובץ שלישי שצריך להיראות כך:
C001 BLA BLA מהקובץ הראשון
C001 ABC ABC מהקובץ השני

C002 FGD DTF מהקובץ הראשון
C002 FSR HREמהקובץ הראשון
C002 FGH WTD מהקובץ השני

C006 DFE FEWמהקובץ הראשון
C006 FEH RWEמהקובץ הראשון
C006 FSW DSA מהקובץ השני

C989 FWE HWRמהקובץ הראשון
C989 OIP JCDמהקובץ השני
מה הדרך הכי פשוטה ברורה ומהירה בכדי לבצע את זה ??
תודה.
 

BravoMan

Active member
עד כמה סדר השורות חשוב?

אם נניח בדוגמה השנייה, עם C002, השורה מהקובץ השני היית בין שתי השורות מהקובץ הראשון במקום בסוף, האם זה היה משנה?
&nbsp
נניח ככה:
C002 FGD DTF מהקובץ הראשון
C002 FGH WTD מהקובץ השני
C002 FSR HREמהקובץ הראשון
 

sharon1003

New member
חשוב

היי bravoman,
אתה שוב מנסה לעזור לי ...
תודה :)
&nbsp
הסדר חשוב,
חשוב לי שהשורה מהקובץ השני תופיע תמיד בסוף ולא באמצע.
אני מאמין שיש כאן אולי איזה משהו משולב של awk עם if / While וכו',
אני לא מכיר את זה ברמה מספיק טובה בשביל לפתור את זה :(
&nbsp
&nbsp
תודה,
 

BravoMan

Active member
מעניין...

1. מה לגבי שמות הקבצים עצמם?
האם אפשר להניח שהשמות הם בסדר כלשהו, מילוני \ מספרי, למשל 1, 2, 3 או A, B, C?
&nbsp
2. וגם לא כ"כ הבנתי: האם אתה רוצה להוסיף בתור עמודה ראשונה את שם הקובץ ממנו הגיע השורה, או שזה היה סתם להבהרה?
&nbsp
בהנחה שהתשובה ל-1 היא שאין סדר, הפתרון היחיד שמצאתי קצת מורכב, וכולל צירוף של awk, sort ו-cut (שים לב, לא cat!)
במידה ויש סדר ניתן להחליף את השימוש ב-awk אם grep פשוט יחסית (מבחינת פרמטרים).
 

sharon1003

New member
להלן התשובות לשאלותיך ...

היי,
&nbsp
אענה על השאלות שלך לפי הסדר.
&nbsp
תשובה לשאלה מס' 1:
מספרי הקבצים פחות חשובים לי, יותר חשוב לי התוכן.
בעיקרון יש לי 2 קבצים שלא משנה איך קוראים להם .... ברצוני ליצור את קובץ מס' 3 ע"פ הדרישות שהוצגו (ארשום אותם שוב בהמשך).
&nbsp
תשובה לשאלה מס' 2:
אני לא רוצה להוסיף בעמודה הראשונה את שם הקובץ (שם הקובץ לא קשור , כמו שרשמת זה היה רק להבהרה).
מה שאני רוצה זה שבקובץ מס' 1 לפי העמודה הראשונה הוא יזהה את המילה , ואז ברגע שתיהיה מילה שונה משורה לשורה (בעמודה הראשונה)
הוא ישתול את השורה המתאימה שבקובץ השני (לפי המילה הראשונה שבעמודה מס' 1).
&nbsp
C01 BLA BLA קובץ מס' 1
C01 BLA FSD קובץ מס' 1
C01 FDF ERR קןבץ מס' 2 (זאת השורה שנוספה בעקבות המילה C01).
&nbsp
&nbsp
C02 fsd BLA קובץ מס' 1
C02 GHT ERR קובץ מס' 2 (זאת השורה שנוספה בעקבות המילה C02).
&nbsp
&nbsp
C03 dtr BLA קובץ מס' 1
C03 ser BLA קובץ מס' 1
C03 XER ERR קןבץ מס' 2 (זאת השורה שנוספה בעקבות המילה C03).
&nbsp
 

BravoMan

Active member
לא שאלתי אם לך זה משנה, אלא אם מחשב יכול

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

בכל מקרה, אחרי מעט מחשבה, הגעתי לפתרון שבצירוף 3 פקודות (אם תרצה את שורת הרווח, תצטרך לשרשר גם סקריפט ה-awk שכתבתי לך פעם שעברה לסוף השורה) עושה את הפעולה בצורה יחסית חסכונית ובלי קשר לשמות הקבצים.

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

כאשר בדרך, נוספת עמודה עם מספר הקובץ, מה שמאפשר לוודא ששורות מקובץ שני ימוינו אחרי שורות מהקובץ הראשון עם עמודה ראשונה זהה (זו שמתחילה ב-C בדוגמה שלך).

להלן הפתרון:
awk 'FNR==1 {FILE_NO++}{print FILE_NO, $0}' 1.txt 2.txt | sort -k2,2 | cut -d" " -f2-
יש קאצ' אחד אחרון בפתרון הזה: הוא עלול לשנות את סדר השורות בעבור קובץ ספציפי, כלומר, אם יש יותר משורה אחת עם עמודה ראשונה זהה בקובץ ראשון, אותן שורות אלולות להופיע בסדר שונה ממה שהן מופיעות בקובץ, אבל עדיין לפני שורות עם אותה התחלה מקובץ 2.

אם סדר השורות חשוב גמרי, אפשר להרחיב את הפתרון.

ועכשיו להסבר:
החלק הראשון עם הפקודה awk מוסיף עמודה זמנית עם מספר סידורי של הקובץ שדרושה כדי שהפקודה הבאה - sort לא תמיד תשים שורות מקובץ 2 אחרי שורות מקובץ 1.
החלק השני (האמצעי) עם sort ממין את השורות לפי העמודה השנייה (למעשה, עמודה ראשונה בקבצים שלך). הבעיה היא, שגם עם הגבלת עמודות, כאשר sort נתקל בשתי שורות זהות מבחינת העמודה המבוקשת, הוא מתעקש להשתמש בשאר השורה כדי למיין, ולכן ללא מספר סידורי של קובץ, שורות מ-2 יכולות להתערבב עם שורות מ-1.

ולבסוף הפקודה cut מורידה את העמודה הזמנית עם מספר הקובץ כדי להשאיר לך פלט נקי.
 
למעלה