0

I have some code that looks like this:

  ################### - Let's call this section 1
  if [ -n "$STUFF_JAVA" ]; then
    __LAUNCHER="$STUFF_JAVA"
  else
    __LAUNCHER="java"
  fi
  ################### - Let's call this section 2
  if [ -n "$JAVA_HOME" ]; then
    # # echo "DEBUG: Using JAVA_HOME"
   _STUFF_JAVA_HOME="$JAVA_HOME"
   _STUFF_JAVA="$_STUFF_JAVA_HOME"/bin/$__LAUNCHER
  else
     echo "testing"
  fi
  ############## - Let's call this section 3
  _STUFF_JAVA_HOME="$JAVA_HOME"
  _STUFF_JAVA="$_STUFF_JAVA_HOME"/bin/$__LAUNCHER
  ##############

I don't understand why section 2 has issues setting the _STUFF_JAVA_HOME variable but section 3 does not? Do I need to use curly brackets or parenthesis somewhere?

I want my code to set the following variables:

_STUFF_JAVA_HOME
_STUFF_JAVA

I don't understand why it gets set in section 3 but not section 2.

For some reason, in section 2, it's not able to pick up the variable to determine the length...

Is there something I am missing?

(I am inexperienced with shell script. I am reading a book and have literally finished chapter 1.)

ilkkachu
  • 138,973

1 Answers1

0
(base) jj@tb-jj:/$ ################### - Let's call this section 1
  if [ -n "$STUFF_JAVA" ]; then
    __LAUNCHER="$STUFF_JAVA"
  else
    __LAUNCHER="java"
  fi
  ################### - Let's call this section 2
  if [ -n "$JAVA_HOME" ]; then
    # # echo "DEBUG: Using JAVA_HOME"
   _STUFF_JAVA_HOME="$JAVA_HOME"
   _STUFF_JAVA="$_STUFF_JAVA_HOME"/bin/$__LAUNCHER
  else
     echo "testing"
  fi

(base) jj@tb-jj:/$ echo "$_STUFF_JAVA"
./Some/Path/bin/java
(base) jj@tb-jj:/$ echo "$_STUFF_JAVA_HOME"
./Some/Path

It appears to be working fine. Can you be more specific with what the undesirable behavior actually IS? Also, you DO have a JAVA_HOME variable set, yes?

Also, I observe you've omitted the _ from _STUFF_JAVA in the Section 1 test and variable assignment. Is this intentional?

And, finally, a -n comparison is verifying that a variable is not null (or, more precisely, that it is a string whose length is -not zero).

This is distinct from a -z comparison (which is testing for a -zero-length string).

Consequently, note that [ -n "$my_var" ] will yield different results than [ -n $my_var ].

(base) jj@tb-jj:/$ [ -n "$BOB" ] && echo 1 # I will produce nothing, because you're expanding $BOB inside a blank \
                                           # string, and then testing if a string is null (it's not). 
(base) jj@tb-jj:/$ [ -n $BOB ] && echo 1 # I will return 1, because you're now testing on an undeclared variable.
1

(Note: I manually set my own JAVA_HOME to ./Some/Path before executing the first two sections of your code)

Hauke Laging
  • 90,279
NerdyDeeds
  • 121
  • 5
  • Please use the plaintext version formatted as code instead of a screenshot. – annahri Jun 12 '23 at 22:29
  • Sorry, @annahri. I was trying to illustrate the results in the terminal proper, as evidence of its effectiveness. I included code formatted transcripts below both screenshots. – NerdyDeeds Jun 12 '23 at 22:35
  • 2
    "I will return 1, because you're now testing on an undeclared variable." Not quite: when the variable is empty (or unset) but unquoted, the single bracket conditional only sees one argument, "-n". With one argument, the test is true if the argument is a non-empty string. "-n" is a non-empty string, so the result is true and "1" is echoed. – glenn jackman Jun 13 '23 at 12:53
  • I consider this a philosophical point. "If a variable falls in the woods, but no one was around to set it..." or perhaps, "what is the value of an unset variable testing?" -n is testing for the polar opposite of -z: it returns True if the length of string is non-zero (where -z returns true if it IS 0). So let me ask you: given that, why does [ -n $BOB ] test true? What is it that $BOB is handing back that the interpreter views as a non-zero length string? (Note: I don't disagree with you; [ -n ] tests true as well. But if it's looking for a string > 0...? I'm genuinely asking) – NerdyDeeds Jun 14 '23 at 16:53
  • (@glennjackman I quote the above from all the gnus that's fit to print: https://www.gnu.org/software/bash/manual/bash.html#Bash-Conditional-Expressions. the question I ask at the end there is mine, & directed at you. I'd have thought it would be the opposite, though. My best guess woulda been it's a typing issue. That an unset BOB is being - what? "coerced"? - into a testable value? A boolean? Which is still not a string value. Is it being read as "False"? Is there an stderr value below the surface which is non-zero? Or is the comparator just sloppy and handing back a true by default? – NerdyDeeds Jun 14 '23 at 17:11
  • @NerdyDeeds, in [ -n $BOB ], if the variable is unset or empty, it disappears during word splitting, and the command that runs is just the same as [ -n ]. That tests the string -n to see if it's empty or not. ([ -n str ] is the same as [ str ]). The test can't tell an unset variable from an empty one. – ilkkachu Jun 14 '23 at 17:20
  • @ilkkachu I totally comprehend that is what's happening. What I'm asking is why it is, under the hood. [ -n $VAR ] is supposed to return true if $VAR is a string with a length that is non-zero. An unset variable is not a string. Nor, were it to BE a string, would one suppose it to be a string with something inside it (thus yielding a length other than zero). WHY is $VAR evaluating out to a true when tested using this flag? – NerdyDeeds Jun 14 '23 at 17:32
  • Never mind, I found the appropriate Posix spec: "If there is no command name, but the command contained a command substitution, the command shall complete with the exit status of the last command substitution performed. Otherwise, the command shall complete with a zero exit status." (https://pubs.opengroup.org/onlinepubs/9699919799.2018edition/utilities/V3_chap02.html#tag_18_09_01). Since the [] is testing the return code of an expression containing an expansion and there is not an actual expression to test, it's testing the return code of the last expansion expression itself. – NerdyDeeds Jun 14 '23 at 17:44
  • @NerdyDeeds, yes, and no. Maybe. The issue is that in [ -n $VAR ], $VAR may produce one or more command line arguments to [. If it produces one, then what you just said holds. If it produces more, it's likely an error from [ (try VAR="foo bar"; [ -n $VAR ]). If it produces none, [ never sees anything but the -n and ]. And in that case it checks to see if -n is nonempty. (try [ "$VAR" ] for various values, or just [ "" ]) – ilkkachu Jun 14 '23 at 17:45
  • @NerdyDeeds, that's not relevant, as there is a command name, it's [. I'm not sure what you refer to with "the return code of an expression". Commands have return codes, and the term expression usually only comes up in the shell wrt. arithmetic expressions. – ilkkachu Jun 14 '23 at 17:47
  • @ilkkachu I don't believe [ is considered a command. An operator or expression modifier of some sort, sure, but not a command in the conventional sense. [[ I think is, but I think [ is an inbuilt term. Consider [[ 'Y' =~ [Yy] ]] && echo 1. Now consider [[ 'N' =~ [ Yy ] ]] && echo 1 Note the error response? "Syntax error in conditional expression." EDIT: Nope, I'm mistaken. It's syntactic sugar for the test command. – NerdyDeeds Jun 14 '23 at 17:58
  • @NerdyDeeds, yes, exactly. [[ is the one that is special. There's a few posts about that on the site. Also about that [ -n $VAR ] thing, note how [ -z $VAR ] and [ -n $VAR ] give the same result if VAR is unset (or set to the empty string, e.g. VAR="" or VAR=). [[ -n $VAR ]] would correctly be false for an unset/empty $VAR, though, exactly because [[ is special. – ilkkachu Jun 14 '23 at 18:19