variablesawkgrepaix

Match pattern by passing a variable to awk as an alternative to grep -B


grep -B does not work on AIX so I am looking for an alternative with awk

I have a file with the following content

05/25/2025       M    301510sa     AIX is vulnerable to information disclosure (CVE-2024-13176) or arbitrary code execution or a denial of service (CVE-2024-9143) due to OpenSSL
  openssl.base                   3.0.15.1000  <  3.0.15.1001
06/15/2025       M    973013sab    AIX is vulnerable to a denial of service (CVE-2025-26466) and a machine-in-the-middle attack (CVE-2025-26465) due to OpenSSH
  openssh.base.server            9.7.3013.1000 <  9.7.3013.1001
06/15/2025       M    973013saa    AIX is vulnerable to a denial of service (CVE-2025-26466) and a machine-in-the-middle attack (CVE-2025-26465) due to OpenSSH
  openssh.base.client            9.7.3013.1000 <  9.7.3013.1001

and I want to get only the following

05/25/2025       M    301510sa     AIX is vulnerable to information disclosure (CVE-2024-13176) or arbitrary code execution or a denial of service (CVE-2024-9143) due to OpenSSL
  openssl.base                   3.0.15.1000  <  3.0.15.1001

I want to pass as parameter the package which in this case is openssl.base and I want to get the above result with the following command but it doesn't work

pkg=“openssl.base”; awk -v var1="$pkg" '/var1/{for(i=1;i<=x;)print a[i++];print}{for(i=1;i<x;i++)a[i]=a[i+1];a[x]=$0;}' x=1 file

I got the command from another site but I have not been able to make it work with what I want How can I find lines before my match if my grep doesn't support the -B option?


Solution

  • First issue to address is the assignment to pkg.

    You're wrapping openssl.base in smart quotes instead of plain double quotes; those double quotes become part of the data and will never match (because the file does not contain smart quotes) so:

    ###### replace this:
    
    pkg=“openssl.base”                # smart quotes
    
    ###### with this:
    
    pkg="openssl.base"                # plain double quotes
    

    Second issue is that /var1/ is looking for the literal string var1. In this case you want to test for the 1st field matching the contents of variable var1 so:

    ###### replace this:
    
    /var1/
    
    ###### with this:
    
    $1 == var1
    

    Updating OP's current awk script with these 2 changes:

    pkg="openssl.base"; awk -v var1="$pkg" '$1==var1{for(i=1;i<=x;)print a[i++];print}{for(i=1;i<x;i++)a[i]=a[i+1];a[x]=$0;}' x=1 file
    

    This generates:

    05/25/2025       M    301510sa     AIX is vulnerable to information disclosure (CVE-2024-13176) or arbitrary code execution or a denial of service (CVE-2024-9143) due to OpenSSL
      openssl.base                   3.0.15.1000  <  3.0.15.1001
    

    OP's awk script is a modified version of this answer and has the downside of some excessive copying of array values.

    This other answer to the same question should be a bit more efficient in that it overwrites array entries in the process of maintaining a rolling list of last N lines. Modifying that answer to work with OP's data and requirement:

    awk -v var1="$pkg" -v N=1 '
    BEGIN      { cl=1 }
    
    $1 == var1 { for (i=cl; i<cl+N; i++)
                     print pLines[i % N]
                 print $0
                 cl=1
               }
    
               { pLines[cl % N] = $0
                 cl++
               }
    ' file
    

    This also generates:

    05/25/2025       M    301510sa     AIX is vulnerable to information disclosure (CVE-2024-13176) or arbitrary code execution or a denial of service (CVE-2024-9143) due to OpenSSL
      openssl.base                   3.0.15.1000  <  3.0.15.1001