Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I want to make sure a file follows the following pattern:

... ... ... foo ... foo_KO ... ... 
... bar ... ... ... ... bar_KO ...

The file is extremely long, so, in other words, I want to make sure of the following rule, in sed terms:

Every time ([a-z]*)_KO is matched, there is another field on the same line whose value is \1.

I hoope I'm clear enough.

I'm on Solaris 10, using ksh.

Example:

intput

... ... ... foo ... foo_KO ... ... 
... bar ... ... ... ... bar_KO ...

output

valid

input

... ... ... foo ... foo_KO ... ... 
... bar ... ... ... ... bar_KO ...
... fubar_KO ... ... ... ... ... 

output

invalid line 3 

or

unmatched pattern fubar_KO
share|improve this question
    
The “_KO”-less variant can be anywhere on the same line or only before the one with “_KO”, as in the example? –  manatwork May 7 '12 at 10:19
    
It can be anywhere –  rahmu May 7 '12 at 10:19
    
What output would you like from the example in your question? –  jw013 May 7 '12 at 10:19
    
something like: 'valid'. Let me edit my question with example input and expected outputs –  rahmu May 7 '12 at 10:20
1  
Can be more than one “_KO”-marked thing in a line? –  manatwork May 7 '12 at 10:23
show 3 more comments

2 Answers

up vote 4 down vote accepted

This will output the line numbers of invalid lines:

sed -n '/\([a-z]\+\).*\1_KO/b;/\([a-z]\+\)_KO.*\1/b;=' input_file

But not deals with multiple “_KO”'s on one line.


This should be more reliable and portable:

awk '{for(i=1;i<=NF;i++)if((s=$i)~/^([a-z]+)_KO/){sub(/_KO$/,"",s);o=0;for(j=1;j<=NF;j++)if($j==s)o=1;if(!o)printf"line %d unmatched %s\n",NR,s}}' input_file

This is trickier, more efficient and supports multiple patterns, but as depends on sorting, locale settings may affect its success:

ruby -nae '$F.sort!.select!{|v|v=~/^[a-z]+(_KO)?$/};$F.each_with_index{|v,k|puts"line #{$.} unmatched #{v}"if v[/^([a-z]+)_KO$/]and$F[k-1]!=$1}' input_file

Basically the same as the above awk solution, but looks less verbose in perl:

perl -nae 'for$k(grep/^[a-z]+_KO$/,@F){print"line $. unmatched $k\n"unless grep{$_ eq substr$k,0,-3}@F}' input_file
share|improve this answer
    
It doesn't seem to work with Solaris sed. Here's the error I'm getting: sed: Label too long: /\([a-z]\+\).*\1_KO/b;/\([a-z]\+\)_KO.*\1/b;=. I'll try to get my hands on GNU sed, but that's not easy to do around here ... –  rahmu May 7 '12 at 10:38
    
The awk script worked perfectly thanks. Do not take this the wrong way, but I don't find it very elegant to bruteforce like this manually over each field. I'm sure you agree. There should be a more elegant way to detect if a matched pattern is repeated more than once on a line. –  rahmu May 7 '12 at 12:28
    
I agree, it looks quite clumsy. But with multiple patterns and various order I see no simpler way for now. –  manatwork May 7 '12 at 12:36
2  
@manatwork you are just awesome with awk/sed :-) –  Nikhil Mulley May 7 '12 at 12:47
add comment

Some cryptic perl:

perl -ne '/(\w+)_KO\b/ && !/\b$1(?!_KO)\b/ && print "invalid line $.: missing $1\n"' filename

/(\w+)_KO\b/ find the "_KO" word and capture the non-KO part into variable $1
!/\b$1(?!_KO)\b/ is true if there is NO "standalone" word without _KO (\b is a word boundary)
If both those conditions are true, print the error message.

To determine if the file is "valid", either

output=$(perl -ne '/(\w+)_KO\b/ && !/\b$1(?!_KO)\b/ && print "invalid line $.: missing $!\n"' filename)
[ -z "$output" ] && echo valid

or

perl -ne '
    BEGIN {$count = 0}
    if (/(\w+)_KO\b/ && !/\b$1(?!_KO)\b/) {print "invalid line $.: missing $!\n"; $count++}
    END {$count == 0 && print "valid\n"}
' filename
share|improve this answer
    
Worked pretty well. I did get some false positives though, for words containing _KO inside them. I added a \b to your pattern matching regex, as per your explanations. I don't know perl syntax, so if I'm mistaken do not hesitate to re-modify. –  rahmu May 7 '12 at 15:07
    
thanks @rahmu, quite right. –  glenn jackman May 7 '12 at 15:13
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.