Awk фильтрация с несколькими полями - PullRequest
1 голос
/ 10 мая 2011

Предположим, у меня есть следующий текстовый файл (он может содержать больше штатов, городов и колледжей:

begin_state
New York
end_state

begin_cities
Albany
Buffalo
Syracuse
end_cities

begin_colleges
Cornell
Columbia
Stony Brook
end_colleges

begin_state
California
end_ state

begin_cities
San Francisco
Sacramento
Los Angeles
end cities

begin_colleges
Berkeley
Stanford
Caltech
end_colleges

Я хочу использовать awk, чтобы отфильтровать все города и перечислить их по штатам или выбрать все колледжи и перечислить их по штатам: Например, если мне нужны города, они должны выводиться следующим образом.

**New York**
Albany
Buffalo
Syracuse
**California**
San Francisco
Sacramento
Los Angeles

Любые предложения приветствуются.

1 Ответ

1 голос
/ 10 мая 2011

Вот два решения в awk.Первый наивный и повторяющийся, но легче следовать и учиться.Последний - попытка уменьшить повторение.

Оба решения хрупки в отношении обработки ошибок в вашем файле данных.Если вы свободны в выборе языка реализации, я предлагаю вам сделать это как-нибудь вроде ruby, perl или python.

Сохранить в файл (например, showinfo.sh) и вызывать с одним аргументом: «города» или"колледжи", чтобы определить режим.Также вы должны перенаправить файл данных в стандартный ввод.

Пример вызова (для любого решения):

./showinfo.sh cities < states.txt
./showinfo.sh colleges < states.txt

Наивное решение:

#!/bin/bash
set -e
set -u
#mode=cities
mode=$1

awk -v mode=$mode '
/begin_state/    {st="states"; next} 
/end_state/      {next} 
/begin_cities/   {st="cities"; next} 
/end_cities/     {next} 
/begin_colleges/ {st="coll"; next} 
/end_colleges/   {next} 

{ 
  if (st=="states") {
    sn=$0; 
  }
  else 
    if (st=="cities") cities[sn]=cities[sn]"\n"$0
    else if (st=="coll") colleges[sn]=colleges[sn]"\n"$0; 
} 

END {
  if (mode=="cities") {
    for (sn in cities) { print "=="sn"=="cities[sn] } ; 
  } 
  else if (mode=="colleges") {
    for (sn in colleges) { print "=="sn"=="colleges[sn] } ; 
  } 
  else { print "set mode either cities or colleges" }
}'

Второе решение, судалено повторение:

#!/bin/bash
set -e
set -u
mode=$1
awk -v mode=$mode '
/begin_/    {st=$1; next} 
/end_/      {st=""; next} 

{ 
  if (st=="begin_state") { sn=$0 }
  else { data[st, sn]=data[st, sn]"\n"$0 }
} 

END {
  for (combo in data) {
    split(combo, sep, SUBSEP);
    type = sep[1];
    state_name = sep[2];
    if (type == "begin_"mode) {
      print "==" state_name "==" data[combo];
    }
  }
}'

Используется входной файл (как я отмечаю, он недавно изменился в вопросе):

begin_state
New York
end_state
begin_cities
Albany
Buffalo
Syracuse
end_cities
begin_colleges
Cornell
Columbia
Stony Brook
end_colleges
begin_state
California
end_state
begin_cities
San Francisco
Sacramento
Los Angeles
end_cities
begin_colleges
Berkeley
Stanford
Caltech
end_colleges

Сессия при запуске первого решения:

$ bash showinfo.sh cities < states.txt 
==New York==
Albany
Buffalo
Syracuse
==California==
San Francisco
Sacramento
Los Angeles
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...