[sed/awk/?]как выделить слово из строки, идущее после заданного слова?

yolki

т.е. имеется файл со строками примерно такого вида:

bla-bla-bla KEYWORD "id" bla-bla-bla
bla-bla-bla KEYWORD "id" bla-bla-bla
bla-bla-bla KEYWORD "id" bla-bla-bla
bla-bla-bla KEYWORD "id" bla-bla-bla

(файл получен из другого при помощи grep "KEYWORD" file)
где bla-bla-bla: произвольный текст разной длины.
KEYWORD - фиксированное слово (KEYWORD)
"id" - идентификатор в кавычках, идентификаторы от строки к строке могут различаться, а могут и повтроятся.
хотелось бы на выдаче получить список этих идетнтификаторов, трубопровод в uniq я уж в состоянии сделать.

slonishka

sed 's/.*KEYWORD "\([0-9]*\)".*/\1/'

slonishka

даже так наверное лучше: sed 's/.*KEYWORD[^"]*"\([0-9]*\)".*/\1/'
а то может после KEYWORD не пробел, а еще какая-нибудь херь.

yolki

идея понятна. почему он всю строку мне печатает. нужно чтобы только id печатал..
id - это буквы-цифры, а не только цифры.

slonishka

ну замени на [a-zA-Z0-9]
почему греп всю строку печатает? ну он всегда так делает по умолчанию.
мб можно заставить подстроку печатать, мне лень ман смотреть.

slonishka

sed 's/.*KEYWORD[^"]*"\([^"]*\)".*/\1/'
вот так вообще все что угодно будет в id :D

yolki

так вопрос в том и состоит, чтобы только подстроку id и напечатать.

yolki

в общем, ничего проще придумать не удалось (awk):

{
KWPOS=index($0,"KEYWORD")
TMPSTR=substr($0,KWPOS+9,200)
IDPOS=index(TMPSTR,"\"")
ID=substr(TMPSTR,1,IDPOS-1)
print ID
}

slonishka

бля. а я тебе что написал?
cat log | grep KEYWORD | sed 's/.*KEYWORD[^"]*"\([^"]*\)".*/\1/'

rolex1993

perl рулит ; )

#!/usr/bin/perl
die "\n\nSYNOPSYS:\n\t$0 input_file\n\n" if (@ARGV < 1);
$inp = $ARGV[0];
die "File $inp doesn't exist" if (!(-e $inp;
open INP, $inp || die "Can't open $inp";
while ($str = <INP>)
{
     print "$1\n" if ($str =~ /\s+KEYWORD\s+"([^"]+)"\s+/);
}
close INP;

serega1604

sed 's/^.*KEYWORD[^"]*"\([^"]*\)".*$/\1/'
может так лучше будет?

yolki

твоё печатает всю строку целиком. моё печатае только id.

pitrik2

твоё печатает всю строку целиком.
дык его не срабатывает
я sed не знаю
но \( ОЧЕНЬ смущает
может все таки просто
без слешей7

ermsoft

Эх... Отвечу всем сразу, раз всё знаю :)
Во-первых,

sed -n 's/.*KEYWORD[^"]*"\([^"]*\)".*/\1/p'

, чтобы не печатать те строки, в которых KEYWORD почему-то отсутствует. (вероятно, поэтому и проблемы).
Во-вторых, \) и \) нужны, потому что это basic RE, а не extended.
В-третьих, нормальное решение на перле будет выглядеть так:

perl -nle '/KEYWORD\s+"(.*?)"/ and print $1'
, а не тот ужас, который там выше написан.

slonishka

bugaga ~/zzz $ cat aaa
bla-bla-bla KEYWORD "id" bla-bla-bla
bla-bla-bla KEYWORD "id" bla-bla-bla
bla-bla-bla KEYWORD "id" bla-bla-bla
bla-bla-bla KEYWORD "id" bla-bla-bla
bugaga ~/zzz $ cat aaa | grep KEYWORD | sed 's/.*KEYWORD[^"]*"\([^"]*\)".*/\1/'
id
id
id
id

честно. =)
слэши перед скобками нужны:
 $ info sed

The `s' Command
===============

The syntax of the `s' (as in substitute) command is
`s/REGEXP/REPLACEMENT/FLAGS'. The `/' characters may be uniformly
replaced by any other single character within any given `s' command.
The `/' character (or whatever other character is used in its stead)
can appear in the REGEXP or REPLACEMENT only if it is preceded by a `\'
character.

The `s' command is probably the most important in `sed' and has a
lot of different options. Its basic concept is simple: the `s' command
attempts to match the pattern space against the supplied REGEXP; if the
match is successful, then that portion of the pattern space which was
matched is replaced with REPLACEMENT.

The REPLACEMENT can contain `\N' (N being a number from 1 to 9,
inclusive) references, which refer to the portion of the match which is
contained between the Nth `\(' and its matching `\)'. Also, the
REPLACEMENT can contain unescaped `&' characters which reference the
whole matched portion of the pattern space. Finally, as a GNU `sed'
extension, you can include a special sequence made of a backslash and
one of the letters `L', `l', `U', `u', or `E'. The meaning is as
follows:

что касается ^$, вроде разницы нет.
как ^.* может отличаться от .* в начале? ну и .*$ от .* в конце.

slonishka

> чтобы не печатать те строки, в которых KEYWORD почему-то отсутствует.
он же написал, что делал grep KEYWORD. =)

ermsoft

> он же написал, что делал grep KEYWORD. =)
Угу, я угадать пытался, почему могло быть
> твоё печатает всю строку целиком. моё печатае только id.

slonishka

ладно, не спорю, KEYWORD мог оказаться не там еще при grep-е.
но не мог же он ПОСТОЯННО оказываться не там, что привело к тому,
что sed ни для одной строки не нашел совпадений и вывел их все, как было. :D

yolki

странно, но под виндой у меня sed одиночные кавычки '' не скушал. :crazy:

rolex1993

code:
perl -nle '/KEYWORD\s+"(.*?)"/ and print $1'
, а не тот ужас, который там выше написан.
хм
а в чем ужас-то?
в том чтот скрипт заменяетвсе эти cat | grep | sed ?
или может быть non-greedy выражение лучше чем просто ([^"]+)?
кроме того реализаций sed'а не одна, а на перле если уж что-то работает, то работать будет везде.

ermsoft

В том, что одноразовые задачи надо решать простыми способами, а не писать программы по 10 строк.
Что если спорить про количество реализаций, стабильных версий перла существует штук где-то 12, начиная с 5.005 (хотя твой код вроде на любой будет работать).
А sed документирован в POSIX.
Что твоя программа не откроет файл с именем '0', угадай почему :)
(лучше уж было <> использовать... Что как раз и делает -n, кстати. Так что моё решение тоже заменяет и cat, и grep.)
Короче, KISS.
PS. Я не защищаю sed, и сам бы в данном случае перлом воспользовался, кстати. Как раз из-за необходимости помнить, что скобки надо экранировать.

slonishka

тут обычно рулит то, чем чаще пользуешься. я такие седы раз по пять в день пишу, когда чо-нибудь ищу в коде. %)

rolex1993

А sed документирован в POSIX.
он может быть и документирован, но какие-то различия между реализацией GNU и в BSD вроде есть
[quote]
Что твоя программа не откроет файл с именем '0', угадай почему
лучше уж было <> использовать
[quote]
скажет что нет такого файла и штатно завершится, и правильно сделает
0 это не имя а значение файлового дескриптора STDIN ; )
почему cat | filter.pl лучше filter.pl filename?

ermsoft

он может быть и документирован, но какие-то различия между реализацией GNU и в BSD вроде есть
Думаю, они POSIX-совместимые.
Ну это не так важно, я уже говорил, что тоже предпочёл бы перл в данной задаче.
Что твоя программа не откроет файл с именем '0', угадай почему
лучше уж было <> использовать
скажет что нет такого файла и штатно завершится, и правильно сделает
0 это не имя а значение файлового дескриптора STDIN ; )
Эээ. Ошибаешься.

mmcleric-desktop:~/temp$ echo 'qewr' >0
mmcleric-desktop:~/temp$ ls -l 0
-rw-r--r-- 1 mmcleric mmcleric 5 2007-11-03 19:05 0
mmcleric-desktop:~/temp$ perl -e '$i = $ARGV[0]; print "File: $i\n"; open INP, $i or die "Cant open $i"; while (<INP>) {print}' 0
File: 0
qewr
mmcleric-desktop:~/temp$ perl -e '$i = $ARGV[0]; print "File: $i\n"; open INP, $i || die "Cant open $i"; while (<INP>) {print}' 0
File: 0
Cant open 0 at -e line 1.

Чтобы указать файловый дескриптор по номеру, надо так писать:
If you specify ’<&=X’, where "X" is a file descriptor number or a filehandle , then Perl will do an equivalent of C’s "fdopen" of that file descriptor (and not call dup(2
почему cat | filter.pl лучше filter.pl filename?
Потому что filter.pl, написанный с использованием <>, будет работать и для cat | filter.pl, и для filter.pl filename, и для filter.pl file1 file2, и для filter.pl *.log.

rolex1993

Что твоя программа не откроет файл с именем '0', угадай почемулучше уж было <> использоватьскажет что нет такого файла и штатно завершится, и правильно сделает0 это не имя а значение файлового дескриптора STDIN ; )Эээ. Ошибаешься.
понял о чем ты
да ну и хрен с ним что не откроется - других что-ли файлов мало : D

apl13

ну замени на [a-zA-Z0-9]
For example, [[:alnum:]] means [0-9A-Za-z], except the latter form depends upon the POSIX locale and the ASCII character encoding, whereas the former is independent of locale and character set.
:umnik: :donot:
Оставить комментарий
Имя или ник:
Комментарий: