2012-02-03 11 views
6

Próbuję wykonać zadanie domowe, które jest ograniczone do używania tylko pliku sed w celu odfiltrowania pliku wejściowego do określonego formatu danych wyjściowych. Tutaj jest plik wejściowy (nazwany stocks):Jak napisać skrypt sed do grep informacji z pliku tekstowego

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 

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

a wyjście musi być:

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

zrobiłem wymyślić rozwiązanie, ale to nie jest wydajne. Oto moja sed skrypt (o nazwie 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 
} 

Komenda że biegnę na powłoce wynosi:

$ sed -nf try.sed stocks 

Moje pytanie brzmi, czy istnieje lepszy sposób korzystania sed aby uzyskać ten sam rezultat ? Skrypt, który napisałem, działa tylko z 7 liniami danych. Jeśli dane są dłuższe, muszę ponownie zmodyfikować mój skrypt. Nie jestem pewien, jak mogę to poprawić, więc proszę o pomoc!

Dzięki za wszelkie zalecenia.

+5

+1 do wpuszczania to zadanie domowe i do tego dziko 's/\ (. * \); ....../'rzecz, którą tam umieściłeś! Powodzenia. – shellter

Odpowiedz

2

Jeszcze jeden sposób korzystania sed:

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

wyjściowa:

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

Objaśnienie:

-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, dziękuję Birei! Nie wiedziałem, że mogę zrobić podwójnie {} i zapomniałem, że mogę użyć zastępczego polecenia w/o g, aby dopasować pierwszy występujący mecz. Nadal mam tu kilka pytań. 1. Dlaczego ostatni blok jest na ostatnim wzorze linii ($)? 2. Do 2. zastąpienia nowej linii. Czy jego celem jest usunięcie pustej linii? 2. W przypadku ostatniej zamiany nowej linii, dlaczego nie zastąpił nowej linii po "MMM"? Dałeś mi świetne wyjaśnienie, ale nadal nie rozumiem celu $ {}. Mam nadzieję, że pomożesz mi to lepiej zrozumieć. Dziękuję bardzo za Twoją pomoc!! – Jaycee

+0

@Jaycee: [1] Zapisuję żądane ciągi w 'przestrzeni wstrzymanej' podczas procesu pliku i tylko w ostatnim wierszu odtwarzam tę zawartość, modyfikuję ją i drukuje. [2] Polecenie 'H' dołącza' \ n' oraz zawartość 'wzorca przestrzeni' do 'przytrzymaj spację', więc na końcu linii zawartość będzie wyglądać tak: '\ nBAC \ nCSCO \ nINTC \ nMSFT \ nVZ \ nKO \ nMMM '. Następnie usuwam najpierw '\ n' i zastępuję pozostałe', ' – Birei

+0

Ahhh ..... Mam to teraz !!!! Dziękuję bardzo!!!!!Fajnie jest używać H i g .... =) Nie wiem, dlaczego mój nauczyciel nie nauczył nas tych poleceń. Jeszcze raz dziękuję!!!!!^O ^ – Jaycee

0

Ten sed polecenie powinno produkować wymaganą moc:

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

lub na Mac:

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

To jest praca domowa. Naprawdę nie powinieneś po prostu dawać mu odpowiedzi. –

+0

Drogi Anubhava, uruchomiłem polecenie, ale dane wyjściowe nie znajdują się w jednym wierszu. Jednym z wyzwań jest zastąpienie całego znaku nowej linii przecinkiem i 1 spacji, z wyjątkiem ostatniej linii. Po ostatnim nie powinno być przecinka. – Jaycee

+0

Tak, mój skrypt zachowuje się dokładnie jak grep -o, ponieważ teraz zdaję sobie sprawę z jego pracy domowej, zostawię resztę skryptu dla ciebie. – anubhava

2

Edit: Mam edytowane mój algorytm, bo zapomniał wziąć pod uwagę nagłówek i stopka (myślałem, że są tylko dla naszej korzyści).

sed, poprzez swój projekt, uzyskuje dostęp do każdej linii pliku wejściowego, a następnie wykonuje wyrażenia na te, które pasują do jakiejś specyfikacji (lub żadnej). Jeśli dostosowujesz skrypt do pewnej liczby linii, zdecydowanie robisz coś złego! Nie napiszę ci skryptu, ponieważ jest to praca domowa, ale ogólnym pomysłem na jeden sposób, aby to zrobić, jest napisanie skryptu, który wykonuje następujące czynności. Pomyśl o porządku w kolejności, w jakiej powinno być scenariusz.

  1. Pomiń pierwsze trzy wiersze, używając d, która usuwa obszar wzorów i natychmiast przechodzi do następnej linii.
  2. Dla każdej linii, która nie jest pustym wierszem, wykonaj następujące kroki. (To wszystko będzie w jednym zestawie nawiasów klamrowych).
    1. Zamień wszystko za pierwszym średnikiem (włącznie z pierwszym, średnikiem) (;) za pomocą polecenia przecinka i przestrzeni (","), używając polecenia s (zamień).
    2. Dołącz bieżącą przestrzeń wzorów do hold buffer (patrz: H).
    3. Usuń przestrzeń wzór i przejść do następnej linii, jak w kroku 1.
  3. dla każdej linii, który dostaje się do tego punktu w skrypcie (powinien być pierwszy pusty wiersz), pobierać zawartość miejsce przechowywania w obszarze wzorów. (To byłoby za nawiasem klamrowym powyżej).
  4. Zastąpić wszystkie nowe linie w przestrzeni wzorów bez niczego.
  5. Następnie należy zastąpić ostatnią przecinkiem i spacją w obszarze wzoru bez niczego.
  6. Na koniec zamknij program, aby nie przetwarzać kolejnych linii. Mój skrypt działał bez tego, ale nie jestem w 100% pewny dlaczego.

To powiedzenie, to tylko jeden sposób, aby to osiągnąć. sed często oferuje różne sposoby różnej złożoności, aby wykonać zadanie. Rozwiązanie, które napisałem tą metodą, ma 10 linii.

Na marginesie nie przeszkadza mi drukowanie (z -n) lub drukowanie ręczne (z p); każda linia jest drukowana domyślnie. Mój skrypt działa tak:

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

@Jaycee Z którą częścią powyższego masz problemy? Chciałbym poprawić moje wyjaśnienie, jeśli potrafię! –

+0

Cześć, Dan, dzięki za podpowiedź.W pierwszym kroku otrzymam wszystkie symbole z przecinkiem i spacją. Ale mam problem z drugim krokiem. Jak uzyskać każdą linię, która nie jest ostatnią linią? Technicznie, MMM nie jest ostatnią linią. ============ jest ostatnią linią. Jestem tak zdezorientowany i naprawdę nie wiem, jak postępować. Czy mógłbyś rozwinąć trochę więcej ??? Dziękuję bardzo za Twoją pomoc! – Jaycee

+0

Mogę uzyskać ostatni z następujących: /[0-9] $/{N N s/\ (. * \);. *;. * \ N \ n \ = */\ 1/gp } – Jaycee

0

To może pracować dla Ciebie:

sed '1d;/;/{s/;.*//;H};${g;s/.//;s/\n/, /g;q};d' stocks 
  • Nie chcemy nagłówki więc niech je usunąć. 1d
  • Wszystkie pozycje danych są ograniczone przez ;, więc skoncentrujmy się na tych liniach. /;/
  • z rzeczy powyżej usunąć wszystko z pierwszego ; do końca linii, a następnie wepchnąć ją w przestrzeń hold (HS) {s/;.*//;H}
  • Gdy dojdziesz do ostatniego wiersza, nadpisać go z HS przy użyciu komenda g, usuń pierwszy znak nowej linii (wygenerowany przez komendę H), zamień wszystkie kolejne znaki nowej linii na przecinek i spację i wypisz, co zostało. ${g;s/.//;s/\n/, /g;q}
  • Usuń wszystko inne d

Oto terminal sesja pokazując przyrostową udoskonalenie budowy sed polecenie:

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 
Powiązane problemy