0

I have the below script saved in bin, which is using to get output based on a defined variable. Currently, this script is running for column 1 and providing output. How can we update this script so it can provide output if it match on either column 1 or 2.

cat ~/bin/POUT

#!/bin/bash

exec awk -v arg=${1:?} '$1==arg' "${@:2}" inputfile

input file-:

 DEV       RETAIL          RETAILDEVNode  
TEST      RETAILTEST       RETAILTESTNode 
TEST       AUDIT            AUDITTESTNode
QA         AUDITQA         AUDITQANode
PROD       SALE            SALEPRODNode
QA         SALEQA           SALETESTNode
QA        FINANCE         FINANCEQANode
PROD      FINANCE         FINANCEPRODNode

Currently getting Expected output-

$ POUT QA
QA         AUDITQA         AUDITQANode
QA         SALEQA           SALETESTNode
QA        FINANCE         FINANCEQANode

Also want output like below (search in column 2 also):

$ POUT AUDITQA
QA         AUDITQA         AUDITQANode

Want output like this also (put any matching value and search in column 2 aslo) ---

$ POUT DITQ QA AUDITQA AUDITQANode

So whatever input is given in variable, it should serach in column 1 and 2 and provide output.

Kusalananda
  • 333,661

2 Answers2

1

Could be:

#! /bin/sh -
export ARG="${1?}"
shift
exec awk '
  BEGIN{
    field = 1
    arg = ENVIRON["ARG"] ""
  }
  $field == arg' "$@" inputfile

Then you can invoke it as POUT AUDITQA field=2 to look for AUDITQA in the second field while keeping your CLI backward compatibility.

A few notes:

  • if you forget quotes around expansions in bash or sh like in your -v arg=${1?}, they are subject to split+glob. It is very bad here as that introduces an arbitrary command execution vulnerability. It's actually one of the examples given at Security implications of forgetting to quote a variable in bash/POSIX shells
  • You can't use -v to pass arbitrary text as -v mangles backslashes. Hence the use of ENVIRON above which doesn't have the problem.
  • note that since awk treats foo=bar.txt arguments as variable assignments, if you have file names containing = characters, you need to pass them as ./foo=bar.txt instead of foo=bar.txt.
  • $field and ENVION["var"] or variables passed via -v are treated as numeric string if they look numerical and == could then end up doing a numeric comparison instead of string comparison. We're concatenating "" to to ENVIRON["ARG"] so it be considered as a string always, so that for instance, if called with 10 as argument, it doesn't match on 10.0 or 010 or 1e1.
1
#!/bin/bash
arg="${1:?}"    # Capture argument value or fail
shift

awk -v arg="${arg//\\/\\\\}" 'index($1, arg) || index($2, arg)' "$@" inputfile

Always double-quote shell variables when you use them. (Always, that is, until you understand why there can occasionally be exemptions. Until then always double-quote.)

The messy assignment of the shell variable $arg to the awk variable arg is to undo awk's backslash processing.

I don't understand why you're passing remaining command line parameters to awk and providing inputfile as a constant source. However, I've left that in place in case it's really intentional.

Chris Davies
  • 116,213
  • 16
  • 160
  • 287
  • 1
    "mangling of backslashes" makes what -v does with them sound like a bad thing rather than the very useful feature that it actually is, i.e. interpreting of escape sequences. If you don't want escape sequences interpreted then instead of trying to escape the escapes by adding "${arg//\\/\\\\}", just don't assign variables using -v, use ENVIRON[] or the arg list with the shell variable as-is., see how-do-i-use-shell-variables-in-an-awk-script. – Ed Morton Apr 23 '23 at 11:40
  • e.g. awk 'index($1, arg) || index($2, arg)' arg="$arg" inputfile – Ed Morton Apr 23 '23 at 11:44
  • 1
    @EdMorton in hindsight "mangling" was probably a bad choice of word. Perhaps "processing" might have been better – Chris Davies Apr 23 '23 at 13:14