2012-02-03 2 views
6

Я пытаюсь выполнить домашнюю работу, которая ограничена только использованием sed для фильтрации входного файла в определенный формат вывода. Здесь входной файл (с именем stocks):Как написать сценарий sed для grep-информации из текстового файла

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 

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

И выход должен быть:

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

Я придумал решение, но это не эффективно. Вот мой sed скрипт (названный 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 
} 

Команда, бегаю по оболочке:

$ sed -nf try.sed stocks 

Мой вопрос, есть ли лучший способ использования СЭД, чтобы получить тот же результат ? Сценарий, который я написал, работает только с 7 строками данных. Если данные более длинные, мне нужно повторно модифицировать мой скрипт. Я не уверен, как я могу сделать это лучше, поэтому я прошу о помощи!

Спасибо за любые рекомендации.

+5

+1 для допуска это домашнее задание, и для этого диком 's/\ (. * \); ....../'thingy вы положили туда! Удачи. – shellter

ответ

2

Еще один способ использования sed:

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

Выход:

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

Объяснение:

-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

Вау, спасибо Бирей! Я не знал, что могу сделать double {}, и я забыл, что могу просто использовать команду replace to/o g для соответствия 1-му встречному совпадению. У меня все еще есть несколько вопросов. 1. Почему последний блок находится на последнем шаблоне строки ($)? 2. Для второй замены новой строки. Его цель - удалить пустую строку? 2. Для последней замены новой строки, почему она не заменила новую строку после «MMM»? Вы дали мне отличное объяснение, но я до сих пор не понимаю цели $ {}. Надеюсь, ты поможешь мне понять это больше. Большое вам спасибо за вашу помощь!! – Jaycee

+0

@Jaycee: [1] Я сохраняю нужные строки в 'hold space' во время процесса файла и только в последней строке восстанавливает это содержимое, модифицирует его и печатает. [2] Команда 'H' добавляет' \ n' плюс содержимое «пространства шаблонов» для «удержания пространства», поэтому в последней строке содержимое будет выглядеть как '\ nBAC \ nCSCO \ nINTC \ nMSFT \ nVZ \ nKO \ nMMM '. Затем я удаляю первый '\ n' и заменяю остальные на', ' – Birei

+0

Ahhh ..... Я получил это сейчас !!!! Огромное спасибо!!!!!Приятно использовать H и g .... =) Не знаю, почему мой учитель не научил нас этим командам. Еще раз спасибо !!!!!^O ^ – Jaycee

0

Эта СЕПГ команда должна произвести ваш необходимый вывод:

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

или на Mac:

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

Это домашнее задание. Вы действительно не должны просто дать ему ответ. –

+0

Уважаемый анубхава, я запустил вашу команду, но вывод не в одной строке. Одна из задач заключается в замене всей новой строки на запятую и 1 пробел, за исключением последней строки. После последнего не должно быть запятой. – Jaycee

+0

Да, мой скрипт ведет себя точно так же, как grep -o, так как теперь я понимаю его домашнюю работу, я оставлю вам остальную часть скрипта. – anubhava

2

Edit: Я редактировал свой алгоритм, так как я не учел заголовок и нижний колонтитул (я думал, что они просто для нашей пользы).

sed по своей конструкции обращается к каждой строке входного файла, а затем выполняет выражения на тех, которые соответствуют определенной спецификации (или никому). Если вы настраиваете свой сценарий на определенное количество строк, вы определенно делаете что-то неправильно! Я не буду писать вам сценарий, поскольку это домашнее задание, но общая идея одного из способов сделать это - написать скрипт, который делает следующее. Подумайте о заказе, так как порядок вещей должен быть в скрипте.

  1. Пропустить первые три строки, используя d, который удаляет пространство рисунка и сразу переходит к следующей строке.
  2. Для каждой строки, которая не является пустой строкой, выполните следующие действия. (Это все будет в одном наборе фигурных скобок.)
    1. Заменить все после и включающую в себя первую точку с запятой (;) с разделителями-и-пространстве («»), используя команду s (заменить).
    2. Добавить текущее пространство шаблона в hold buffer (см. H).
    3. Удалите шаблон пространство и перейти к следующей строке, как и в шаге 1.
  3. Для каждой линии, которая попадет в этот момент в сценарии (должна быть первой пустой строкой), извлекать содержимое удерживайте пространство в пространстве шаблонов. (Это будет после фигурных скобок выше.)
  4. Substitute все новые строки в пространстве шаблонов без ничего.
  5. Затем замените последнюю запятую и пространство в пространстве шаблонов ничем.
  6. Наконец, выйдите из программы, чтобы не обрабатывать больше строк. Мой скрипт работал без этого, но я не уверен на 100% почему.

Это, как говорится, это только один из способов его решения. sed часто предлагает различные способы различной сложности для выполнения задачи. Решение, которое я написал с помощью этого метода, составляет 10 строк.

В качестве примечания я не беспокоюсь о том, чтобы подавлять печать (с -n) или ручную печать (с p); каждая строка печатается по умолчанию. Мой сценарий работает так:

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

@Jaycee С какой частью выше вы столкнулись? Я хотел бы улучшить свое объяснение, если смогу! –

+0

привет, Дэн, спасибо за подсказку.Для первого шага я получаю все символы с запятой и пробелом. Но мне трудно сделать второй шаг. Как получить каждую строку, которая не является последней строкой? Технически, MMM не является последней строкой. ============ - последняя строка. Я так смущен и действительно не знаю, как действовать. Не могли бы вы рассказать немного больше ??? Большое вам спасибо за вашу помощь! – Jaycee

+0

Я могу получить последнее сообщение: /[0-9] $/{N N s/\ (. * \);. *;. * \ N \ n \ = */\ 1/Г.П. } – Jaycee

0

Это может работать для вас:

sed '1d;/;/{s/;.*//;H};${g;s/.//;s/\n/, /g;q};d' stocks 
  • Мы не хотим, чтобы заголовки, так что давайте удалить их. 1d
  • Все элементы данных разделены на ;, поэтому давайте сосредоточимся на этих линиях. /;/
  • Из горних удалить все, от первого ; до конца строки, а затем наполнить его прочь в трюме пространство (HS) {s/;.*//;H}
  • Когда вы дойдете до последней строки, перезаписать его с HS с помощью команду g, удалите первую новую строку (сгенерированную командой H), замените все последующие строки новой строки запятой и пробелом и распечатайте оставшиеся. ${g;s/.//;s/\n/, /g;q}
  • Удалить все остальное d

Вот терминальная сессия показывает добавочное уточнение построения патча в следующей команде:

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 
Смежные вопросы