Print unique specific text form a line if it meet the search criteria

Viewed 73

I Have the following input.txt file

service commands 1 description 'Desc 1 patternid com3'
service commands 2 description 'Desc 1 patternid com3 from err1'
service commands 3 description 'Desc 2 patternid com3 from err2'
service commands 4 description 'Desc 2 patternid com3 from err3'

service commands 1000 description 'to value1 patternid from 1000'
service commands 1001 description 'to value1 patternid from 1001'

service commands 2000 description 'Desc 3 patternid com'
service commands 2001 description 'Desc 3 patternid com2 from err1'
service commands 2002 description 'Desc 4 patternid com2'
service commands 2003 description 'Desc 4 patternid com2 from err1'

service commands 4000 description 'output patternid to com1'
service commands 5000 description 'input to com1'
service commands 6000 description 'input to com2'

I want with awk to take the unique descriptions from lines where the service commands number meet the criteria between 1-1000 and 2000-4000 But I want only the description text that is before the word "patternid"

I have found this for the search

awk -F'_' '($1>1999 && $1<4000){print}' input.txt

But I can't make to search in 3nd filed and for multiple values

I can print the description with

awk -F"service commands |description |'" '/service commands/ && /description /{for(i=1; i<=NF; ++i) printf"%s", $i ; print""}' input.txt

But this not what i want

My desire output is

Desc 1
Desc 2
Desc 3
Desc 4

How can I do it with one awk command or a combination of them?

2 Answers
$ awk '
    ( ((1 < $3) && ($3 < 1000)) || ((2000 < $3) && ($3 < 4000)) ) &&
    sub(/[^\047]+\047/,"") && sub("patternid.*","") && !seen[$0]++
' file
Desc 1
Desc 2
Desc 3
Desc 4

1st solution: With your shown samples only, could you please try following.

awk '
/[0-9]+ description.*Desc[[:space:]]+[0-9]+[[:space:]]+patternid/ && (($3>=1 && $3<=1000) || ($3>=2000 && $3<=4000)) && !arr[$5,$6]++{
  sub(/^\047/,"",$5)
  print $5 OFS $6
}
'  Input_file

Explanation: Checking if regex pattern [0-9]+ description.*Desc[[:space:]]+[0-9]+[[:space:]]+patternid is found in current line(as per OP's requirement), then checking conditions either 3rd field value comes in range of 1 to 1000 OR 3rd field range is coming from 2000 to 4000 AND then checking a condition if 5th and 6th fields combine are NOT present in array then print that value(to get unique values in output).



2nd solution:

awk '
match($0,/^service commands [0-9]+[[:space:]]+description.*Desc [0-9]+ patternid/) && (($3>=1 && $3<=1000) || ($3>=2000 && $3<=4000)){
  val=substr($0,RSTART,RLENGTH)
  sub(/.*Desc/,"Desc",val)
  sub(/ patternid/,"",val)
  if(!arr[val]++){ print val }
}'  Input_file

Explanation: Adding detailed explanation for above(following is only for explanation purposes, for running code use above).

# Starting awk program from here.
awk '

    # Using match function to match regex to make sure line has exact format
    # needed by OP. Then checking conditions either 3rd field value comes in
    # range of 1 to 1000 OR 3rd field range is coming from 2000 to 4000.
    match($0, /^service commands [0-9]+[[:space:]]+description.*Desc [0-9]+ patternid/) &&
            (($3 >= 1 && $3 <= 1000) || ($3 >= 2000 && $3 <= 4000)) {

        # Creating val which has sub string of matched regex.
        val = substr($0, RSTART, RLENGTH)

        # Globally substituting everything till Desc with Desc in val here.
        gsub(/.*Desc/, "Desc", val)

        # Substituting space patternid with NULL in val here.
        sub(/ patternid/, "", val)

        # Checking condition if entry is not already present in arr then print val here.
        if ( !seen[val]++ ) {
            print val
        }
    }

# Mentioning Input_file name here.
' Input_file
Related