1

After research, Im not certain this is possible in a bash script. The most likely reason ive found is due to bash's order of shell expansions. (maybe?)

What i would like to happen, Is the ability to enable/disable redirection (>) of a statement via a prior variable.

for example: the printf output below should be (redirected >) based upon what the variable $SendGrafana contains.
However this example code does not work:

SendGrafana=" > /dev/tcp/192.168.1.242/5062"

awk -v vars="$vars" 'BEGIN{printf "output.api %s \n", vars;}' $SendGrafana

i was hoping the code above would work just like this:

awk -v vars="$vars" 'BEGIN{printf "output.api %s \n", vars;}' > /dev/tcp/192.168.1.242/5062

Additionally- When i run the script with set -x (for debugging), i see that single quotes (') are being wrapped around just the redirect (>) , which i assume is the problem, as nothing gets sent to my netcat listener. I have read that this is only for user readability when using set -x, however the problem remains.

Here is the relevant output with set -x enabled:

+ awk -v vars=3 'BEGIN{printf "output.api %s \n", vars;}' '>' /dev/tcp/192.168.1.242/5062

(note the '>' )

I have tried many methods, both at the variable declaration as well as at the variable expansion, but all fail to redirect the output to 192.168.1.242:5062 when script is called. Thank you


EDIT BELOW- (adding this part which was in my comments, as i was trying to keep the question brief, but was suggested it should be here):

To add some more context: the reason im even using this $SendGrafana variable, as opposed to no variable and literally > /dev/tcp/192.168.1.242/5062 after each awk statement- is so i can easily set $SendGrafana= " " , and my script will output to STDOUT (and not send to 192.168.1.242 via > /dev/tcp/192.168.1.242/5062). I need the output on STDOUT ONLY during debugging / test adding new statements.

  • To add some more context- the reason im even using this $SendGrafana variable, as opposed to no variable and literally " > /dev/tcp/192.168.1.242/5062" after each awk statement-
    is i have many (30x +) of these awk -v vars=... and i would like the ability to easily turn off the "> /dev/tcp/192.168.1.242/5062" parts, for when im debugging / adding new awk statements.
    IE i can easily set $SendGrafana= " " , and the script will output to STDOUT (and not send to 192.168.1.242) which is what id like ONLY during debugging / adding new statements. tks
    – James Gaul Aug 19 '20 at 21:10
  • 1
    Please "add some more context" by [edit]ing your question, not by writing comments. Make it easy for someone to read your question in one go. – Chris Davies Aug 19 '20 at 21:25
  • 3
    when you debug script with -x and you can see additional single quotes, that single quotes neither break your strings nor they actually exist - that is just to illustrate you how the script see your strings (for example whitespaces causes word splitting) in your case the '>' is just a literal character and doesn't get evaluated that way you assume – alecxs Aug 19 '20 at 21:26
  • 1
    Despite you bolding up some text at the beginning of the question I still don't see what it is you want to do. Please describe it in terms of what you're trying to achieve, not in terms of commands doing (or not doing) something. – Chris Davies Aug 19 '20 at 21:31
  • 2
    As you have witnessed, you cannot put > in a variable and expect it to be identified as a redirection operator after expansion. Data may go in variables, not syntax. – Quasímodo Aug 19 '20 at 21:37
  • Thank you all- it appears the consensus is this does not seem to be possible. Also, @alecxs i have edited to question to hopefully be more clear and concise. – James Gaul Aug 19 '20 at 22:29
  • instead of prefix eval (to evaluate a literal > from string) you can pipe your command through a function for tee (with a little if then else decision on $SendGrafana) that would keep it close to the desired suffix syntax – alecxs Aug 19 '20 at 23:27
  • 1
  • 1

1 Answers1

2

The problem is indeed order of evaluation.

This just puts the text into the command line: it is too late for shell to implement the redirection.

paul $ j=" > foo.txt "
paul $ echo Words Here $j
Words Here > foo.txt
paul $ ls -l foo.txt
ls: cannot access 'foo.txt': No such file or directory

This causes the shell to re-evaluate the whole command.

paul $ eval echo Words Here $j
paul $ ls -l foo.txt
-rw-r--r-- 1 paul paul 11 Aug 19 22:38 foo.txt
paul $ cat foo.txt
Words Here
paul $ 

The eval built-in can be difficult to use correctly, and I avoid it wherever possible. Your command gets evaluated twice (once as args to eval, and again by eval itself), which can make your quoting difficult and tedious (particularly where awk is involved, where single and double quotes are already needed.) Also, mistakes can cause your variables to be executed as commands, with unintended consequences. More here:

unix.stackexchange.com/questions/278427/why-and-when-should-eval-use-be-avoided-in-shell-scripts

Example added:

One suggestion from the StackExchange link I posted is to have shell make a new file descriptor, and direct that to the target first.

This is a somewhat overdressed test script.

#! /bin/bash

#.. First arg to script is -l for test runs.

#.. For your live action. Grafana="/dev/tcp/192.168.1.242/5062"

#.. For my demo here. Grafana="./foo.txt"

rm -f foo.txt

if [[ "${1}" = "-l" ]]; then exec 7>&1 shift 1 else exec 7>"${Grafana}" fi

vars="${@}" #.. Rest of args to output.

awk -v vars="$vars" 'BEGIN{printf "output.api %s \n", vars;}' 1>&7

ls -l foo.txt && cat foo.txt

And a test with logging to terminal, and then to a named file/device.

Paul--) ./Swit -l Easy Living
output.api Easy Living 
ls: cannot access 'foo.txt': No such file or directory
Paul--) ./Swit Easy Living
-rw-r--r-- 1 paul paul 24 Aug 20 09:22 foo.txt
output.api Easy Living 
Paul--) 

You can leave fd 7 open, and use it multiple times in the script. You can close it with exec 7>&-

Paul_Pedant
  • 8,679
  • is aliasing of any use maybe? – alecxs Aug 19 '20 at 23:36
  • Aliasing is just a text replacement, so I guess not helpful. – Paul_Pedant Aug 20 '20 at 07:56
  • eval is not deprecated at all, and only causes injection attacks (like any command that can interpret any code in any language including printf, [, sh, perl, sed...) when used improperly. – Stéphane Chazelas Aug 20 '20 at 08:41
  • I wouldn't say that variable expansion "puts text into the command line", since that really sounds like something that would happen before the command line is parsed for operators etc., and it's exactly the opposite. Alias expansion happens earlier though, and it is more like just putting text there, it happens before operators are parsed from the command line. Try e.g. with alias foo='ls >' and then foo bar; cat bar. – ilkkachu Aug 20 '20 at 08:54
  • And yes... eval is not deprecated in the computing sense, in that it's still a defined and standard feature, not one that is being removed or replaced with something else. We could discuss the other meanings of that word, but in the context, it's just confusing to say it would be deprecated. – ilkkachu Aug 20 '20 at 08:57
  • Revised to summarise the issues without the 'deprecated'. – Paul_Pedant Aug 20 '20 at 09:04
  • Of course, wrapping all the complicated stuff (like an awk program) inside a function, means you can avoid almost all the quoting issues when you eval myFunction > target. – Paul_Pedant Aug 20 '20 at 14:55