0

Let assume I have something like below:

eval link='/var/lib/${XYZ}/test' # string from another text file

XYZ is just for the the example and it could be anything like below:

eval link='/var/lib/${MY_OWN_VAR}/test' # single quote here not double quotes
eval link='/var/lib/${WHAT_EVER}/test'

Is it possible to error out if XYZ is not set? or is there any other way to figure out if XYZ is set or not?

I have looked at this, but the assumption there is that you know the variable name. In my case I have no control over what would be in the string to be evaluated.

UPDATE

To be clear, all the strings that needs to be evaluated are from a text file. basically a program reads a text file and outputs the evaluated strings.

All I am trying here is to figure out a way to gracefully catch "unbound variable" error while evaluating any string. basically what set -u does but gracefully.

pmoubed
  • 3,842
  • 10
  • 37
  • 60
  • I mentioned in my question that I looked at that, and it doesn't fit my criteria. – pmoubed Jan 30 '19 at 17:05
  • 3
    There is `set -u` to complain if you use an undefined variable, but it comes with a few [caveats](https://mywiki.wooledge.org/BashFAQ/112). – Benjamin W. Jan 30 '19 at 17:08
  • @PMoubed Please share your code because it’s hard to know what you’re trying to do. Do you want to check any Bash file for unset variables? How can you use a variable in a string without having its name? – bfontaine Jan 30 '19 at 17:17
  • so...your question is that you assume a string may have a variable embedded, but you are getting it post-parse and the variable might not have had a value? Can you scan for //? – Paul Hodges Jan 30 '19 at 17:18
  • @PaulHodges you are right, but assume you may have it at any place in the string. – pmoubed Jan 30 '19 at 17:20
  • @BenjaminW I have tried set -u but is there a way to gracefully do this? – pmoubed Jan 30 '19 at 17:25
  • If you have a sting that might have had a value already parsed into it, but possibly an empty one, then no, there's no way to look at the string after the fact and see whether a variable that was embedded *somewhere* maybe had no value. – Paul Hodges Jan 30 '19 at 17:28
  • If you have access to the string *before* it parses you can use one of the parameter expansion modifiers, but after the fact, you're out of luck. – Paul Hodges Jan 30 '19 at 17:29
  • 1
    Why are you using `eval`? – chepner Jan 30 '19 at 17:30
  • 3
    "I have no control over what would be in the string to be evaluated." This is a recipe for disaster. Invoking `eval` on unknown content is perhaps the biggest possible error you will ever make. – William Pursell Jan 30 '19 at 17:31
  • Any other way without using eval then? If a program reads a text file that includes all strings that might have variables and outputs actual strings what would be the best way to catch if a variable is not set? – pmoubed Jan 30 '19 at 17:47
  • What do you mean by "outputs the evaluated strings"? The examples you have given are assignments to variable link which I wouldn't expect to produce any output. – jhnc Jan 30 '19 at 19:09
  • @jhnc if XYZ is set to 'something' then the string will be evaluated to /var/lib/something/test – pmoubed Jan 30 '19 at 19:32
  • So, the file only contains the `'...'` part, not the assignment? Where are the variables set? In the text file, or somewhere else? – jhnc Jan 30 '19 at 19:45
  • @jhnc in my case there are some logic before this which sources other files and the variable are from those files. – pmoubed Jan 30 '19 at 19:53

2 Answers2

1

You can test the eval in a subshell before performing it for real:

assign_if_defined(){
    echo 1>&2 "testing $1=$2"
    outvar="$1"
    input=${2@Q}
    err=$(exec 2>&1; set -u; eval "${outvar}=${input@P}")
    if [ -z "$err" ]; then
        echo 1>&2 "eval test succeeded: doing for real"
        eval "${outvar}=${input@P}"
    else
        echo 1>&2 "eval test failed: not doing for real"
        echo 1>&2 "error: $err"
    fi
}

A=set
assign_if_defined link1 "'"'"\/${A}/'
echo link1=$link1

unset B
assign_if_defined link2 '/$B/'
echo link2=$link2

It seems that the @Q/@P transformations first appeared in bash 4.4. Using them means that quoting is much simplified. If using an older version of bash, you could try normal quoting (eval "${outvar}=\"${input}\"") but the code will fail if input contains special characters (as the first example).

jhnc
  • 11,310
  • 1
  • 9
  • 26
0

Well I don't know exactly how much control (or knowledge) you do have on the strings, but can't you just test if it's empty?

VAR=mydirectory
str=/var/lib/${VAR}/test             # valid
str2=/var/lib/${NONEXISTANT}/test    # invalid

if [[ "$str" = "/var/lib//test" ]] ;
then
    echo 'is_empty';
else
    echo 'is_set';
fi;

The only downfall is that the test will fail if you receive a var that is set but empty, e.g. VAR=""

brunorey
  • 2,135
  • 1
  • 18
  • 26
  • I was hoping there would be a flag for eval to catch the error. This won't work for me. let's assume all the strings are from a text file. – pmoubed Jan 30 '19 at 18:14