Помогите реализовать с помощью awk & sed или Perl.
Есть текстовый файл с содержимым такого вида:.......
abba babba affa aggga assa
BMW mercedes benz.car germany
BMW zma rexton.zma russia
tadda galla dalla malla
........В этом файле между словами BMW и mercedes несколько пробелов, а между словами mercedes и benz стоит одинарный пробел, а между car и germany - несколлько пробелов. Нужно вытащить из этого файла и поместить в другой файл записи типа "mercedes benz", отыскав эту строчку по начальному полю "BMW" и комбинации ".car".
Помогите пожалуйста это сделать. Трудность вызывает то, что mercedes benz содержит пробел между словами, а так же то что нужно избавиться от .car.
Заранее спасибо!
Известно, что интересующая нас запись стоит сразу же после BMW, но заранее не известно, состоит она из одного слова (mercedes) или из двух разделенных пробелом (mercede benz). Нужно вытащить то, что лежит между BMW и .car.
>отыскав эту строчку по начальному полю "BMW" и комбинации ".car".perl -ne 'print "$1\n" if /^BMW\s+(.*?)\.car/'
Лучше конечно прочитать man perlre для понимания. Но все же прокоментирую
^ - начало строки
BMW - дословно
\s+ - один и больше пробельных символов
(.*?) - _нежадный_ захват всего подряд
\.car - .car
Разница между жадным и нежадным захватом:
$ perl -ne 'print "$1\n" if /^BMW\s+(.*?)\.car/'
BMW mercedes benz.car benz.car germany
mercedes benz
$ perl -ne 'print "$1\n" if /^BMW\s+(.*)\.car/'
BMW mercedes benz.car benz.car germany
mercedes benz.car benz
Спасибо за быстрый ответ!
Пытаюсь реализовать с помощью sed:
sed -ne '/^BMW\s+(.*?)\.car/p' test.txt не ищет. В чем проблема?
>Спасибо за быстрый ответ!
>Пытаюсь реализовать с помощью sed:
>sed -ne '/^BMW\s+(.*?)\.car/p' test.txt не ищет. В чем проблема?
>Видимо в том, что sed использует другую билиотеку регулярных выражений - соответствующую стандарту IEEE Std 1003.2
man re_formatРегулярные выражения perl имеют больший функционал.
>Спасибо за быстрый ответ!
>Пытаюсь реализовать с помощью sed:
>sed -ne '/^BMW\s+(.*?)\.car/p' test.txt не ищет. В чем проблема?
>sed -n 's/^BMW\s\+\(.*\)\.car.*/\1/p' test.txt
>>Спасибо за быстрый ответ!
>>Пытаюсь реализовать с помощью sed:
>>sed -ne '/^BMW\s+(.*?)\.car/p' test.txt не ищет. В чем проблема?
>>
>
>sed -n 's/^BMW\s\+\(.*\)\.car.*/\1/p' test.txtВсе равно не ищет.
>>>Спасибо за быстрый ответ!
>>>Пытаюсь реализовать с помощью sed:
>>>sed -ne '/^BMW\s+(.*?)\.car/p' test.txt не ищет. В чем проблема?
>>>
>>
>>sed -n 's/^BMW\s\+\(.*\)\.car.*/\1/p' test.txt
>
>Все равно не ищет.Попробуйте так: sed -n 's/^BMW[ \t]*\(.*\)\.car.*/\1/p'
>Попробуйте так: sed -n 's/^BMW[ \t]*\(.*\)\.car.*/\1/p'Спасибо! Работает, но выдает нужное поле в той колонке, из которой было вырезано - в данном случае в колонке 2,то есть результат:
$> sed -n 's/^BMW[ \t]*\(.*\)\.car.*/\1/p'
$> mercedes benz
>Спасибо! Работает, но
>,то есть результат:Стоп! Всем спасибо, ошибка найдена: пользователь не включил мозги и не rtfm.
Всем - спасибо, расходитесь уже, не задерживайтесь. :-/
Спасибо! Результат есть!
>perl -ne 'print "$1\n" if /^BMW\s+(.*?)\.car/'Спасибо! Работает!
Есть еще один вопрос. Пусть есть файл вида:..................................
Name Interval Datum Name Ellipsoid Name Semi-major axis
__________________________________________________________________________________________________________
Aurora Secondary 10 min WGW-84 WGW-84 6378137.0000Name Inv. flattening Shift Shift Type Projection
__________________________________________________________________________________________________________
Aurora Secondary 298.2572221 WGW-84 -> HDA-90 Bursa Wolf ZONE 52S
...................................Как например искать Shift Type, а выводить то, что написано под Shift Type - Bursa Wolf?
Слово Bursa Wolf содержит пробел между словами. Данные, которые требуется вытаскивать, ищутся по заголовку (например Shift Type), а берется то, что располагается точно снизу - Bursa Wolf. Слова могут состоят из пробелов. Как это сделать?
К сожалению все сместилось - не удалось показать файл. Попробую еще раз:Datum Name Ellipsoid Name
WGW-84 WGW-84Shift Shift Type
HDA-90 Bursa Wolf
>Datum Name Ellipsoid Name
>WGW-84 WGW-84
>
>Shift >Shift Type
>HDA-90 Bursa WolfСколько строк? 5?
>К сожалению все сместилось - не удалось показать файл. Попробую еще раз:
>
>
>Datum Name Ellipsoid Name
>WGW-84 WGW-84
>
>
>Shift
>Shift Type
>HDA-90 Bursa WolfРазделитель полей TAB или пробел??
>Разделитель полей TAB или пробел??Разделитель полей - множественные пробелы. Количество строк в файле заранее не известною Здесь приведен лишь фрагмент файла.
Существенная деталь:
Bursa Wolf располагается точно под Shift Type (то есть буква B под буквой S), WGW-84 располагается точно под Ellipsoid Name (то есть буква W под буквой E).
Ellipsoid Name и Shift Type не являются последними столбцами - столбцы есть и справа.
Между строками WGW-84 и Shift расстояние - 2 пустые строки.................
Datum Name Ellipsoid Name ....
WGW-84 WGW-84
Shift Shift Type ....
HDA-90 Bursa Wolf
...................
[c0der@xxx ~]$ cat TEST
Name Interval Datum Name Ellipsoid Name
Semi-major axis
__________________________________________________________________________________________________________
Aurora Secondary 10 min WGW-84 WGW-84
6378137.0000Name Inv. flattening Shift ShiftType Projection
__________________________________________________________________________________________________________
Aurora Secondary 298.2572221 WGW-84 -> HDA-90 Bursa Wolf ZONE 52S
[c0der@xx ~]$ sed -n '/ShiftType/{n;n;s/[ t]\{2,\}/|/g;s/[^|]*|[^|]*|[^|]*|\([^|]*\)|.*/\1/p}' <TEST
Bursa WolfФорматирование, возможно, всё испортит... Короче, надо вас сами пробовать. Вот дока по sed: http://www.cs.utk.edu/~vose/c-stuff/sed_tutorial.html Читайте, пробуйте и у вас всё получится.
Вот алгоритм решения вашей задачи на sed:
- найти строку, в которой есть фраза ShiftType (/ShiftType/)
- считать следующую строку (n)
- считать следующую строку (n)
- теперь строка через одну от найденной у нас. Нужно "выкусить из неё 4 столбец
+ заменяем повторяющиеся два и более раз пробелы/табуляции во всей строке на что-то уникальное (s/[ \t]\{2,\}/|/g)
+ теперь наш уникальный знак является разделителем полей, по регэкспу выкусываем из него только четвёртое поле
- выводим результат
>[оверквотинг удален]
>- найти строку, в которой есть фраза ShiftType (/ShiftType/)
>- считать следующую строку (n)
>- считать следующую строку (n)
>- теперь строка через одну от найденной у нас. Нужно "выкусить из
>неё 4 столбец
> + заменяем повторяющиеся два и более раз пробелы/табуляции во всей
>строке на что-то уникальное (s/[ \t]\{2,\}/|/g)
> + теперь наш уникальный знак является разделителем полей, по регэкспу
>выкусываем из него только четвёртое поле
>- выводим результатможет так
-bash-3.00$ cat 111.txt
Datum Name Ellipsoid Name ....
WGW-84 WGW-84
Shift Shift Type ....
HDA-90 Bursa Wolf
...................-bash-3.00$ cat 111.txt |sed -n '/Shift\ Type/ {
n
s/[ \t]\{2,\}/+/g
p
}'|awk -F+ '{print $2}'
>[оверквотинг удален]
>Shift Shift Type
> ....
>HDA-90 Bursa Wolf
> ...................
>
>-bash-3.00$ cat 111.txt |sed -n '/Shift\ Type/ {
>n
>s/[ \t]\{2,\}/+/g
>p
>}'|awk -F+ '{print $2}'Это 100% работает в Solaris10
>>-bash-3.00$ cat 111.txt |sed -n '/Shift\ Type/ {
>>n
>>s/[ \t]\{2,\}/+/g
>>p
>>}'|awk -F+ '{print $2}'
>
>Это 100% работает в Solaris10Правильно ли я понял?
$> cat test.txt |sed -n '/Shift\ Type/{ns/[ \t]\{2,\}/+/gp}'|awk -F+ '{print $2}'
>[оверквотинг удален]
>>>n
>>>s/[ \t]\{2,\}/+/g
>>>p
>>>}'|awk -F+ '{print $2}'
>>
>>Это 100% работает в Solaris10
>
>Правильно ли я понял?
>
>$> cat test.txt |sed -n '/Shift\ Type/{ns/[ \t]\{2,\}/+/gp}'|awk -F+ '{print $2}'У меня так не работает поетому пришлось писать на разных строках...
>>$> cat test.txt |sed -n '/Shift\ Type/{ns/[ \t]\{2,\}/+/gp}'|awk -F+ '{print $2}'Когда автор слепил весь текст в одну строку и у меня не стало работать ;) Потому что для разделения команд нужно использовать точку с запятой (ну или на новой строке писать, чтобы солярка понимала).
>У меня так не работает поетому пришлось писать на разных строках...
Автор не сообщил ни версию sed'а ни ОС, так что я привёл пример на основе Linux'а. По идее, если автору нужно это на Соляре запускать, то он должен был это сообщить.
>Соляре запускать, то он должен был это сообщить.Спасибо за замечание. Да, мне нужно запустить на Solaris 10.
>-bash-3.00$ cat 111.txt |sed -n '/Shift\ Type/ {
>n
>s/[ \t]\{2,\}/+/g
>p
>}'|awk -F+ '{print $2}'sed -n '/Shift\ Type/ {
n
s/[ \t]\{2,\}/+/g
p
}' <111.txt |awk -F+ '{print $2}'cat тут совершенно не нужен.
>[оверквотинг удален]
>>p
>>}'|awk -F+ '{print $2}'
>
>sed -n '/Shift\ Type/ {
>n
>s/[ \t]\{2,\}/+/g
>p
>}' <111.txt |awk -F+ '{print $2}'
>
>cat тут совершенно не нужен.Это кому как удобно...ИМХО
>Это кому как удобно...ИМХОСпасибо! Извините, но есть небольшая корректировка к файлу. В файле есть разделитель между
Datum Name и WGW-84, Shift и HDA-90 и т.д.
.................
Datum Name Ellipsoid Name ....
---------------------------------------------
WGW-84 WGW-84
Shift Shift Type ....
---------------------------------------------
HDA-90 Bursa Wolf
...................Получилось, что скрипт вытаскивает этот разделитель теперь :-(
>Спасибо! Извините, но есть небольшая корректировка к файлу. В файле есть разделитель
>между [...]
>Получилось, что скрипт вытаскивает этот разделитель теперь :-(А у меня это было предусмотрено ;-)) Сличайте мой скрипт и скрипт от Arpo. ;-))
Подсказка: нужно два n
>Подсказка: нужно два nOгромное спасибо, работает! :-) А если Shift Type встречается несколько раз, как вывести только то, что встретилось первый раз. Заранее спасибо!
>А если Shift Type встречается несколько раз, как вывести только то, что встретилось первый раз. Заранее спасибо!Добавьте q по вкусу :-)
>Добавьте q по вкусу :-)Спасибо! И последнее - как теперь посчитать количество совпадений (то что было найдено при помощи sed и awk)?
>Спасибо! И последнее - как теперь посчитать количество совпадений (то что было
>найдено при помощи sed и awk)?Трудно сказать, вариантов много и мы не знаем деталей. Можно в awk прям и считать, что он там находит, можно в шелле переменную увеличивать. Скорее всего вам wc -l нужно.. он строчки считает.
>Трудно сказать, вариантов много и мы не знаем деталей. Можно в awk
>прям и считать, что он там находит, можно в шелле переменную
>увеличивать. Скорее всего вам wc -l нужно.. он строчки считает.И еще один момент: если есть несколько реализаций поски текста с помощью sed&awk и есть несколько реализаций поиска в Perl, как их лучше объединить?
Хочу добавить, что конечной целью является построение отчетов.
>И еще один момент: если есть несколько реализаций поски текста с помощью
>sed&awk и есть несколько реализаций поиска в Perl, как их лучше
>объединить?Ну, например, так:
FROM_PERL=`perl ... | wc -l`
FROM_AWK=`awk ... | wc -l`
FROM_SED=`sed ... | wc -l`printf 'Всего найдено %u\n' "`expr $FROM_PERL + $FROM_AWK + $FROM_SED`"
Спасибо всем авторам за помощь! Все очень сильно пригодилось! Было интересно и познавательно! :-) Спасибо!
Попутно встретилась еще одна проблема. Если файл имеет немного другое строение:
...........................*****************Projection******************
Datum Name Ellipsoid Name ....
---------------------------------------------
WGW-84 Bursa Wolf
QWQ90 Flow Burs
... ...*****************Translation*****************
Shift Shift Type ....
---------------------------------------------
HDA-90 Bursa Wolf
FDS-70 Flow Burs
... ................................
Нужно в секции Projection отыскать Ellipsoid Name и вывести все поля под ним - Bursa Wolf,Flow Burs и т.д. до секции Translation. Количество этих полей под Ellipsoid Name заранеее не известно.
Если в примере ранее использовалось n;n для считывания вниз 2-строк, то теперь не ясно как сместиться вниз на заранее не известное количество строк и вывести их.
>Попутно встретилась еще одна проблема. Если файл имеетГм, Вам там небольшой Windows на sed-е написать не надо будет? А то одна строчка скрипта всё обрастает "подробностями", а понимание не приходит??
Думаю, что нужно обозначить некий блок /Projection/,/Translation/ и уже в этом блоке применить:
$> cat test.txt | sed -n '/Ellipsoid\ Name/ {n;n;s/[ \t]\{2,\}/+/g;p;}'|awk -F+ '{print $2}'
Но как передать этот блок sed?
У меня работает, вот так:[c0der@xxx ~]$ cat TEST
*****************Projection******************
Datum Name Ellipsoid Name ....
---------------------------------------------
WGW-84 Bursa Wolf
QWQ90 Flow Burs
... ...*****************Translation*****************
Shift Shift Type ....
---------------------------------------------
HDA-90 Bursa Wolf
FDS-70 Flow Burs
You have new mail.
[c0der@xxx ~]$ sed -n '/Projection/{n;/Ellipsoid Name/{n;:l n;/Translation/q;s/[^[:space:]]\+[[:space:]]\+\(.*\)/\1/p;bl}}' TEST
Bursa Wolf
Flow Burs
...
[c0der@xxx ~]$Разбирайтесь как работает, адаптируйте под ваш Солярис :)
В кратце: тут организован этакий цикл -- до тех пор пока в строке нет слова Translation выполняются некие действия (замена, печать).
>В кратце: тут организован этакий цикл -- до тех пор пока в
>строке нет слова Translation выполняются некие действия (замена, печать).Сложно понять 2 вложения! А не покажете для начинающего только одно вложение? Например по Projection найти Bursa Wolf?
Спасибо всем! Было позновательно и интересно! :-) Отдельное спасибо phpcoder'у за терпение! :-) Тема закрыта!