4

Is there any way to modify a shell variable inside awk block of code?

--------- [shell_awk.sh]---------------------
 #!/bin/bash

shell_variable_1=<value A>
shell_variable_2=<value B>
shell_variable_3=<value C>

awk 'function A(X)
{ return X+1 }
{ a=A('$shell_variable_1')
  b=A('$shell_variable_2')
  c=A('$shell_variable_3')
  shell_variable_1=a
  shell_variable_2=b
  shell_variable_3=c
}' FILE.TXT
--------- [shell_awk.sh]---------------------

This is a very simple example, the real script load a file and make some changes using functions, I need to keep each value before change into a specific variable, so then I can register into MySQL the before and after value.

The after value is received from parameters ($1, $2 and so on).

The value before I already know how to get it from the file.

All is done well, except the shell_variable been set by awk variable. Outside from awk block code is easy to set, but inside, is it possible?

0

1 Answer 1

7

No program -- in awk, shell, or any other language -- can directly modify a parent process's memory. That includes variables. However, of course, your awk can write contents to stdout, and the parent shell can read that content and modify its own variables itself.


Here's an example of awk that writes key/value pairs out to be read by bash. It's not perfect -- read the caveats below.

#!/bin/bash

shell_variable_1=10
shell_variable_2=20
shell_variable_3=30

run_awk() {
        awk -v shell_variable_1="$shell_variable_1" \
            -v shell_variable_2="$shell_variable_2" \
            -v shell_variable_3="$shell_variable_3" '
        function A(X) { return X+1 }
        { a=A(shell_variable_1)
          b=A(shell_variable_2)
          c=A(shell_variable_3) }
        END {
          print "shell_variable_1=" a
          print "shell_variable_2=" b
          print "shell_variable_3=" c
        }' <<<""
}

while IFS="=" read -r key value; do
        printf -v "$key" '%s' "$value"
done < <(run_awk)

for var in shell_variable_{1,2,3}; do
  printf 'New value for %s is %s\n' "$var" "${!var}"
done

Advantages

  • Doesn't use eval. Content such as $(rm -rf ~) in the output from awk won't be executed by your shell.

Disadvantages

  • Can't handle variable contents with newlines. (You could fix this by NUL-delimiting output from your awk script, and adding -d '' to the read command).
  • A hostile awk script could modify PATH, LD_LIBRARY_PATH, or other security-sensitive variables. (You could fix this by reading variables into an associative array, rather than the global namespace, or by enforcing a prefix on their names).
  • The code above uses several ksh extensions also available in bash; however, it will not run with POSIX sh. Thus, be sure not to run this via sh scriptname (which only guarantees POSIX functionality).
Sign up to request clarification or add additional context in comments.

4 Comments

Thanks a lot for the answer, I will adapt into my script and make some tests, as soon as possible I'll return the results
It works well your script, was a very nice model. Unfortunately, my script need to load a file, and by column position (not delimiter position), so to do the trick I needed to use read to open file by FD, read line by line, and then use it with printf -v of your read example, all that separeted by funcitons. I tried to do a simple example, but I failed, and my final script is protected by law, reason why I just explained without code. Thanks for the help.
You shouldn't need that sort of workaround: The entire reason I put the prints in the END statement was to run them only after you were finished processing lines in any input file. You did remove the <<<"" when replacing it with the redirection from your input file, right?
By the way, if you were to end up calling awk once per line of input, I'd suggest that you'd be better off implementing your processing in native bash instead. See mywiki.wooledge.org/BashFAQ/100 to get started with some of the kinds of operations one might otherwise look first at awk for.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.