Как написать сценарий sed для извлечения информации из текстового файла - PullRequest
6 голосов
/ 03 февраля 2012

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

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

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

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

Ответы [ 4 ]

2 голосов
/ 03 февраля 2012

Редактировать: Я отредактировал свой алгоритм, так как я не учел верхний и нижний колонтитулы (я думал, что они были только для нас).

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

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

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

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

$ sed -f companies.sed companies 
BAC, CSCO, INTC, MSFT, VZ, KO, MMM
2 голосов
/ 04 февраля 2012

Еще один способ использования 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 голосов
/ 04 февраля 2012

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

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

Вот сеанс терминала, показывающий пошаговое уточнение построения команды 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
0 голосов
/ 03 февраля 2012

Эта команда sed должна выдать необходимый вывод:

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

ИЛИ на Mac:

sed -En '/[0-9]+$/{s/^([^;]*).*$/\1/p;}' file.txt
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...