0

I have large number of bash variable in ch.sh

$ cat ch.sh
BBG=`tput setab 0`
RBG=`tput setab 1`
GBG=`tput setab 2`
.
.
.
$ cat abc
asd
bsd
csd
.
.
.

and I want to access from awk without declaring awk -v for every variable. Does any method exist? I tried this

source ch.sh
awk `
#Let s[asd]="B"
ta=s[$0] "BG" #s is awk array sowehow created by other file
#colour print of line in abc
` abc

Please suggest some method.

  • 3
    If they are environment variables (you don't say so), they are available as ENVIRON["varname"]. Also, could you please post functional code? The code that you've written in the question now contains errors. – Kusalananda Sep 26 '20 at 10:11
  • 2
    If you have a large number of bash variables that you want to access from awk then your awk code is tightly coupled to your bash code and so is highly likely to be bad software. You might want to rethink your design to better separate what you're doing in bash from what you're doing in awk. – Ed Morton Sep 26 '20 at 10:19
  • 1
    That doesn't tell us much, it certainly doesn't explain why you have a file with a pile of shell variables that you need to access within an awk script (If you need them in shell, why do you also need them in awk? If you need them in awk, why are they defined in a shell script?). If you can show a minimal example of bash+awk code that does whatever it is you're trying to do along with concise, testable sample input and expected output then we can best advise you of how to do that the right way. – Ed Morton Sep 26 '20 at 10:24
  • 1
    You still haven't shown a small bash+awk program that demonstrates what you're trying to do. What makes the contents of ch.sh "bash variables" instead of just tag="value" pairs that you could read from awk anyway though? – Ed Morton Sep 26 '20 at 10:33
  • 3
    I see you asked this same question on SO a little earlier and it got closed there for being unclear. You should have taken that feedback and tried to improve the question before just asking it again essentially as-is on a different forum. – Ed Morton Sep 26 '20 at 11:30
1

You could, if you really, really had to (but please read Ed's comment), write a wrapper script that would read a file with variables and add them as -v options:

#/bin/bash

## The first argument is the file with the variables
varFile=$1
## Remove the first argument from the $@ array
shift;

## read the file and add the variables as -v declarations
while IFS="=" read -r var value; do
  varString=$varString" -v $var=${value} "
done < "$varFile"

## Run awk, with the -v declarations and whatever you
## gave on the command line.
awk $varString "$@"

If you save that script as runAwk.sh in your $PATH and make it executable (chmod a+x /home/auth/bin/runAwk.sh), you can then run:

runAwk.sh variables.txt 'awk command' data 

For example, given these two files:

$ cat variables.txt 
var1=bob
var2=foo
var3=baz

$ cat data
1 2
3 4
5 6

You can run:

$ foo.sh variables.txt '{print var1,var2,var3,$2;}' data 
bob foo baz 2
bob foo baz 4
bob foo baz 6

IMPORTANT: this will fail if you have spaces or other whitespace in your variable values. For example, it cannot deal with this:

var1='something with spaces'

If you really need to deal with such values, you should rethink your approach and not try to mix languages. Or, if you cannot, use Ed Morton's clever trick and read the variables into a native awk array.

  • 1
    It'd be more robust if you populated a varArray instead of a varString and you could then access it's contents as awk "${varArray[@]}" (i.e. quoted/protected) instead of awk $varString (exposed/prone to nasal demons :-) ). Warning: I haven't tested that statement! – Ed Morton Sep 26 '20 at 10:57
  • 2
    @EdMorton true, but I took the easy way out and just suggest the OP use your approach for more complex values. It just gets more complicated than it's worth and would be so much simpler with a different approach in a single language. – terdon Sep 26 '20 at 10:58
2

It sounds like you're just thinking about this wrong and all you really have is a file of tag="value" pairs in ch.sh so try this:

$ echo 7 |
awk '
    NR==FNR {
        tag = val = $0
        sub(/[[:space:]]*=.*/,"",tag)
        gsub(/^[^=]+=[[:space:]]*"?|"?[[:space:]]*$/,"",val)
        ch[tag] = val
        next
    }
    {
        tag = "var2"
        print ch[tag], $0
    }
' ch.sh -
zsd 7

and if that's not all you need then edit your question to provide a minimal example of bash+awk code that demonstrates what it is you're trying to do.

  • I edited my question. This is homework question. So I can't give full details. – user429329 Sep 26 '20 at 12:26
  • Yes you can, just make up some sample input, output, and a script that demonstrates the problem. You might want to take a look at using-awk-to-color-the-output-in-bash/64046525#64046525 – Ed Morton Sep 27 '20 at 13:26
1

Assuming your ch.sh file contains valid shell variable assignments, you can export those variables to the environment and then reference them in your AWK script using the ENVIRON associative array.

Given this content for abc:

asd
bsd
csd

and this content for ch.sh:

BBG=`tput setab 0`
RBG=`tput setab 1`
GBG=`tput setab 2`

a purely illustrative Bash script could be:

set -a
. ./ch.sh
set +a
awk '
  BEGIN {
    s["abc"] = "B"
    s["bsd"] = "G"
    s["csd"] = "R"
  }
  {
    ta = ENVIRON[s[$0] "BG"]
    printf("%s%s%s%s", ta, $0, ENVIRON["BBG"], ORS)
  }
' abc

set -a instructs the shell to mark all the newly created or modified variables for export (they would not be available to awk otherwise).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy