2012-02-03 42 views
6

Tôi đang cố gắng làm bài tập ở nhà bị hạn chế chỉ sử dụng sed để lọc tệp đầu vào sang định dạng đầu ra nhất định. Dưới đây là các tập tin đầu vào (tên stocks):Làm cách nào để viết tập lệnh sed vào thông tin grep từ tệp văn bản

Symbol;Name;Volume 
================================================ 

BAC;Bank of America Corporation Com;238,059,612 
CSCO;Cisco Systems, Inc.;28,159,455 
INTC;Intel Corporation;22,501,784 
MSFT;Microsoft Corporation;23,363,118 
VZ;Verizon Communications Inc. Com;5,744,385 
KO;Coca-Cola Company (The) Common;3,752,569 
MMM;3M Company Common Stock;1,660,453 

================================================ 

Và đầu ra cần phải được:

BAC, CSCO, INTC, MSFT, VZ, KO, MMM 

tôi đã tìm ra một giải pháp, nhưng nó không hiệu quả. Dưới đây là sed kịch bản của tôi (tên try.sed):

/.*;.*;[0-9].*/ { N 
N 
N 
N 
N 
N 
s/\(.*\);.*;.*\n\(.*\);.*;.*\n\(.*\);.*;.*\n\(.*\);.*;.*\n\(.*\);.*;.*\n\(.*\);.*;.*\n\(.*\);.*;.*/\1, \2, \3, \4, \5, \6, \7/gp 
} 

Lệnh mà tôi chạy trên vỏ là:

$ sed -nf try.sed stocks 

Câu hỏi của tôi là, là có một cách tốt hơn để sử dụng sed để có được kết quả tương tự ? Kịch bản tôi viết chỉ hoạt động với 7 dòng dữ liệu. Nếu dữ liệu dài hơn, tôi cần phải sửa đổi lại tập lệnh của mình. Tôi không chắc làm thế nào tôi có thể làm cho nó tốt hơn, vì vậy tôi ở đây yêu cầu giúp đỡ!

Cảm ơn mọi đề xuất.

+5

+1 cho thừa nhận điều này là bài tập về nhà và cho hoang dã mà 's/\ (. * \); ....../'thingy bạn đặt trong đó! Chúc may mắn. – shellter

Trả lời

2

Thêm một cách sử dụng sed:

sed -ne '/^====/,/^====/ { /;/ { s/;.*$// ; H } }; $ { g ; s/\n// ; s/\n/, /g ; p }' stocks 

Output:

BAC, CSCO, INTC, MSFT, VZ, KO, MMM 

Giải thích:

-ne    # Process each input line without printing and execute next commands... 
/^====/,/^====/ # For all lines between these... 
{ 
    /;/    # If line has a semicolon... 
    { 
    s/;.*$//  # Remove characters from first semicolon until end of line. 
    H    # Append content to 'hold space'. 
    } 
}; 
$     # In last input line... 
{ 
    g    # Copy content of 'hold space' to 'pattern space' to work with it. 
    s/\n//   # Remove first newline character. 
    s/\n/, /g  # substitute the rest with output separator, comma in this case. 
    p    # Print to output. 
+0

wow, cảm ơn bạn Birei! Tôi không biết tôi có thể làm đôi {} và tôi quên tôi chỉ có thể sử dụng lệnh w/o g thay thế để khớp với kết quả trùng khớp thứ nhất. Tôi vẫn còn một số câu hỏi tại đây. 1. Tại sao khối cuối cùng nằm trên mẫu dòng cuối cùng ($)? 2. Đối với sự thay thế thứ hai của dòng mới. Là mục đích của nó để loại bỏ dòng sản phẩm nào? 2. Đối với sự thay thế cuối cùng của dòng mới, làm thế nào nó không thay thế dòng mới sau "MMM"? Bạn đã cho tôi một lời giải thích tuyệt vời nhưng tôi vẫn không hiểu mục đích của $ {}. Hy vọng bạn có thể giúp tôi hiểu hơn. Cảm ơn rất nhiều vì sự giúp đỡ của bạn!! – Jaycee

+0

@Jaycee: [1] Tôi lưu các chuỗi mong muốn trong 'không gian lưu trữ' trong quá trình của tệp và chỉ trong dòng cuối cùng khôi phục nội dung đó, sửa đổi và in. [2] 'lệnh H' gắn' \ n' cộng nội dung của 'không gian mô hình' thành 'không gian tổ chức', vì vậy ở dòng cuối cùng nội dung sẽ như thế nào '\ nBAC \ nCSCO \ nINTC \ nMSFT \ nVZ \ NKO \ nMMM '. Sau đó, tôi xóa '\ n' đầu tiên và thay thế phần còn lại của chúng bằng', ' – Birei

+0

Ahhh ..... Tôi đã nhận nó ngay !!!! Cảm ơn bạn rất nhiều!!!!!Thật tuyệt khi sử dụng H và g .... =) Không chắc tại sao giáo viên của tôi không dạy chúng ta những mệnh lệnh này. Cám ơn bạn một lần nữa!!!!!^O ^ – Jaycee

0

lệnh sed này nên sản xuất sản lượng yêu cầu của bạn:

sed -rn '/[0-9]+$/{s/^([^;]*).*$/\1/p;}' file.txt 

HOẶC trên Mac:

sed -En '/[0-9]+$/{s/^([^;]*).*$/\1/p;}' file.txt 
+4

Đó là bài tập về nhà. Bạn thực sự không nên chỉ cho anh ta một câu trả lời. –

+0

Kính gửi anubhava, tôi đã chạy lệnh của bạn nhưng đầu ra không nằm trong một dòng. Một trong những thách thức là thay thế tất cả các dòng mới thành dấu phẩy và 1 dấu cách trừ dòng cuối cùng. Không được có dấu phẩy sau dấu phẩy cuối cùng. – Jaycee

+0

Có kịch bản của tôi cư xử chính xác như grep -o, kể từ bây giờ tôi nhận ra một bài tập về nhà của tôi, tôi sẽ để lại phần còn lại của kịch bản cho bạn. – anubhava

2

Edit: tôi đã chỉnh sửa thuật toán của tôi, vì tôi đã bỏ qua để xem xét các tiêu đề và chân trang (tôi nghĩ chúng chỉ vì lợi ích của chúng tôi).

sed, theo thiết kế của nó, truy cập mọi dòng của tệp đầu vào và sau đó thực hiện các biểu thức trên các biểu thức khớp với một số đặc điểm kỹ thuật (hoặc không có). Nếu bạn đang điều chỉnh kịch bản của mình thành một số dòng nhất định, bạn chắc chắn đang làm điều gì đó sai! Tôi sẽ không viết cho bạn một kịch bản vì đây là bài tập về nhà, nhưng ý tưởng chung cho một cách để đi về nó là viết một kịch bản thực hiện những điều sau đây. Hãy suy nghĩ về thứ tự như thứ tự mọi thứ nên có trong một kịch bản.

  1. Bỏ qua ba dòng đầu tiên bằng cách sử dụng d, sẽ xóa không gian mẫu và chuyển ngay sang dòng tiếp theo.
  2. Đối với mỗi dòng không phải là dòng trống, hãy thực hiện các bước sau. (Tất cả điều này sẽ nằm trong một bộ ngoặc nhọn.)
    1. Thay thế mọi thứ sau và bao gồm dấu chấm phẩy đầu tiên (;) bằng dấu phẩy và dấu cách (",") sử dụng lệnh s (thay thế).
    2. Nối không gian mẫu hiện tại vào hold buffer (xem H).
    3. Xóa không gian mô hình và chuyển sang dòng tiếp theo, giống như ở bước 1.
  3. Đối với mỗi dòng mà được đến thời điểm này trong kịch bản (nên là dòng trống đầu tiên), truy xuất nội dung của không gian lưu trữ vào không gian mẫu. (Điều này sẽ sau dấu ngoặc nhọn ở trên.)
  4. Thay thế tất cả dòng mới trong không gian mẫu không có gì.
  5. Tiếp theo, thay thế dấu phẩy và dấu cách cuối cùng trong vùng mẫu không có gì.
  6. Cuối cùng, thoát khỏi chương trình để bạn không xử lý thêm bất kỳ dòng nào. Kịch bản của tôi làm việc mà không có điều này, nhưng tôi không chắc chắn 100% lý do tại sao.

Điều đó đang được nói, đó chỉ là một cách để thực hiện. sed thường cung cấp các cách khác nhau về độ phức tạp khác nhau để hoàn thành nhiệm vụ. Một giải pháp tôi đã viết với phương pháp này dài 10 dòng.

Lưu ý, tôi không bận tâm việc in ấn (với -n) hoặc in thủ công (với p); mỗi dòng được in theo mặc định. Kịch bản của tôi chạy như thế này:

$ sed -f companies.sed companies 
BAC, CSCO, INTC, MSFT, VZ, KO, MMM 
+0

@Jaycee Bạn đang gặp vấn đề gì ở trên? Tôi muốn cải thiện lời giải thích của mình nếu có thể! –

+0

hi, Dan, cảm ơn cho gợi ý.Đối với bước đầu tiên, tôi muốn có được tất cả các biểu tượng bằng dấu phẩy và dấu cách. Nhưng tôi đang gặp khó khăn để thực hiện bước thứ hai. Làm thế nào để tôi nhận được mỗi dòng không phải là dòng cuối cùng? Về mặt kỹ thuật, MMM không phải là dòng cuối cùng. ============ là dòng cuối cùng. Tôi rất bối rối và thực sự không biết cách tiến hành. Bạn có thể vui lòng xây dựng thêm một chút ??? Cảm ơn rất nhiều vì sự giúp đỡ của bạn! – Jaycee

+0

Tôi có thể lấy số cuối cùng như sau: /[0-9] $/{N N s/\ (. * \);. *;. * \ N \ n \ = */\ 1/GP } – Jaycee

0

Điều này có thể làm việc cho bạn:

sed '1d;/;/{s/;.*//;H};${g;s/.//;s/\n/, /g;q};d' stocks 
  • Chúng tôi không muốn tiêu đề vì vậy hãy xóa chúng. 1d
  • Tất cả các mục dữ liệu được phân tách bằng ; vì vậy hãy tập trung vào các dòng đó. /;/
  • Trong số những điều trên xóa tất cả mọi thứ từ ; đầu tiên đến cuối dòng và sau đó nhét nó đi trong không gian giữ (HS) {s/;.*//;H}
  • Khi bạn nhận được đến dòng cuối cùng, ghi đè lên nó với HS sử dụng lệnh g, xóa dòng mới đầu tiên (được tạo bởi lệnh H), thay thế tất cả các dòng mới tiếp theo bằng dấu phẩy và dấu cách và in ra những gì còn lại. ${g;s/.//;s/\n/, /g;q}
  • Xóa mọi thứ khác d

Dưới đây là một phiên terminal hiển thị tinh tế gia tăng của việc xây dựng một lệnh sed:

cat <<! >stock # paste the file into a here doc and pass it on to a file 
> Symbol;Name;Volume 
> ================================================ 
> 
> BAC;Bank of America Corporation Com;238,059,612 
> CSCO;Cisco Systems, Inc.;28,159,455 
> INTC;Intel Corporation;22,501,784 
> MSFT;Microsoft Corporation;23,363,118 
> VZ;Verizon Communications Inc. Com;5,744,385 
> KO;Coca-Cola Company (The) Common;3,752,569 
> MMM;3M Company Common Stock;1,660,453 
> 
> ================================================ 
> ! 
sed '1d;/;/!d' stock # delete headings and everything but data lines 
BAC;Bank of America Corporation Com;238,059,612 
CSCO;Cisco Systems, Inc.;28,159,455 
INTC;Intel Corporation;22,501,784 
MSFT;Microsoft Corporation;23,363,118 
VZ;Verizon Communications Inc. Com;5,744,385 
KO;Coca-Cola Company (The) Common;3,752,569 
MMM;3M Company Common Stock;1,660,453 
sed '1d;/;/{s/;.*//p};d' stock # delete all non essential data 
BAC 
CSCO 
INTC 
MSFT 
VZ 
KO 
MMM 
sed '1d;/;/{s/;.*//;H};${g;l};d' stock # use the l command to see what's really there! 
\nBAC\nCSCO\nINTC\nMSFT\nVZ\nKO\nMMM$ 
sed '1d;/;/{s/;.*//;H};${g;s/.//;s/\n/, /g;l};d' stock # refine refine 
BAC, CSCO, INTC, MSFT, VZ, KO, MMM$ 
sed '1d;/;/{s/;.*//;H};${g;s/.//;s/\n/, /g;q};d' stock # all done! 
BAC, CSCO, INTC, MSFT, VZ, KO, MMM 
Các vấn đề liên quan