2

New in bash script, have to write a function to check if the first given parameter is empty. Output error message if it is empty, otherwise success. Use return-statement and the variable $? Output should for example like this: ./test.sh -> Script failed; ./test.sh hallo -> Script OK. Thank you!

This is what i have now:

check_parameter() {
  var=$1

  if [ -z ${var} ]; then
    return 1
  else
    return 0
  fi

  if [ $?== 0 ]; then
    echo " OK. "

  else
    echo " failed. "
  fi
}
check_parameter $1

It seems like the ìf [ -z $var ]or ìf [ -z ${var} ] doesn't work.

cchi
  • 71
  • 6
  • `$?==` must be `$? ==` (a space is missing). Otherwise Bash reports a syntax error on that statement. – axiac Oct 04 '19 at 13:50
  • @axiac you were right but nothing changed after that. – cchi Oct 04 '19 at 13:59
  • 1
    It was a comment revealing an error, not an answer to your question. That `if` is dead code, anyway; both branches of the previous `if` contain `return` and those `return` make the function complete without running anything else. – axiac Oct 04 '19 at 14:34
  • 1
    Your second `if` statement will never be executed; the first one returns from the function one way or the other. – chepner Oct 04 '19 at 14:38
  • `if [ -z ${var} ]` does not work because when `$var` is empty or not set, it becomes `if [ -z ]` and this is invalid (syntax error). Remember that `-z` checks if the **string** it receives as argument is empty. Put a string after it and it works. – axiac Oct 04 '19 at 14:40
  • 2
    You need to quote arguments: `if [ -z "$var" ]` and `if [ -z "${var}" ]`. Otherwise you will pass no argument to `-z` instead of an empty argument. ***Always quote!*** – ceving Oct 04 '19 at 14:47

4 Answers4

5

Note that a variable can be defined, but have an empty value; that is, you can distinguish between check_parameter and check_parameter "".

That said, you can handle either using a one-line parameter expansion.

check_parameter () {
    : ${1?Parameter required}
}

or

check_parameter () {
    : ${1:?Non-empty parameter required}
}

In both cases, the call check_parameter will have an exit status of 1 and display the given error message. Only in the second case will check_parameter "" fail and display the error message.

Note, though, that the construct will cause the function to simply return if executed in an interactive shell. In a non-interactive shell, the shell itself will exit as soon as the function returns, so it is slightly different from explicitly checking and using return if the variable is not set.

chepner
  • 497,756
  • 71
  • 530
  • 681
  • thanks so much @chepner, I tried your code and it works great, but it seems like it doesn't have the return statement. and i cannot tell if ```${1:?}```the same as ```$?``` – cchi Oct 06 '19 at 19:43
  • 1
    The purpose of `${name:?...}` is to do nothing if the variable is set, or else exit. I did fail to test this from a script; if you run the function from an interactive shell, it simply returns from the function with an exit status of 1. If you run the function from a script, though, it does in fact exit the script itself, rather than simply returning from the function. – chepner Oct 06 '19 at 22:26
2

You need to separate the function. Try that.

function check_parameter() {
  var=$1

  if [ -z ${var} ]; then
    return 1
  else
    return 0
  fi
}

function scriptStatus(){
      if [ $? == 0 ]; then
          echo "Script OK. "
      else
          echo "Script failed. "
      fi
}

check_parameter $1
scriptStatus
tripleee
  • 175,061
  • 34
  • 275
  • 318
  • 1
    The first function could be simplified to just `check_parameter () { [ -z "${var}" ]; }`; the conditional and the explicit `return` statements are completely redundant. Notice also [When to wrap quotes around a shell variable?](https://stackoverflow.com/questions/10067266/when-to-wrap-quotes-around-a-shell-variable) (the braces around `{var}` are basically useless too). – tripleee Oct 05 '19 at 05:16
  • @tripleee thanks so much. I think this answer meet all the conditions that the question given. I know the return statements are redundant but it was in the question. – cchi Oct 06 '19 at 19:46
1

I think what it is looking for is something like this:

check_parameter() {
  test -z "${1}"
  if [ $? == 0 ]; then
    echo 'Script Failed'
    return 1
  fi
  echo 'Script OK'
  return 0
}

This could be less complicated, but with the requirement of

Use return-statement and the variable $?

it seems that it's necessary to do test separately from checking $?.

Z4-tier
  • 7,287
  • 3
  • 26
  • 42
  • https://stackoverflow.com/questions/36313216/why-is-testing-to-see-if-a-command-succeeded-or-not-an-anti-pattern – tripleee Oct 04 '19 at 16:27
  • @tripleee Please re-read the question and my answer, specifically where I stated `This could be less complicated...`. The answer @chepner posted is clearly the best approach in practice. However, the question states to use `$?` and a return statement. Do you have a non-contrived way of answering the question as it is stated? Please post an answer that does that, and I will gladly upvote it. – Z4-tier Oct 04 '19 at 20:40
  • I can't say I understand the intent of the OP really. Probably chepner's answer is the information they actually needed. – tripleee Oct 05 '19 at 05:04
  • @tripleee I was assuming it was a homework exercise, so better to just answer the question as it's given while taking note that the constraints lead to a less concise solution... Although calling it an 'anti-pattern' is some pretty wild hyperbole. – Z4-tier Oct 05 '19 at 16:42
  • It's a common pattern and it's a bad habit which many beginners pick up for no good reason. That's what anti-pattern means. – tripleee Oct 05 '19 at 17:59
  • The GoF authors that coined the term 'anti-pattern' actually state that a bad habit alone does not qualify. There needs to be some negative consequence that makes the solution ineffective, and that isn't the case here. I agree, it's not the best path to the end goal, but OP gave some additional requirements, and this is actually the only answer that satisfies those. – Z4-tier Oct 06 '19 at 02:55
1

Perhaps your instructor is actually looking for

check_parameter() {
  if ! [ -z "$1" ]; then
    echo "$0: Script OK" >&2
    return 0
  else
    rc=$?
    echo "$0: Script failed" >&2
    return "$rc"
  fi
}

if by itself already examines $? behind the scenes; but this takes care of preserving the exact error code - did [ -z ... ] fail with 1, or 2, or 255? - and relaying that back to the caller in case the precise failure code matters to them.

In production code, chepner's answer is what you should actually use to check for a missing parameter; but this answer is a common and useful recipe for how to handle errors in shell scripts generally. Take care to preserve the original error code and communicate it back to the caller, and print diagnostic messages to standard error, with the script's name visible in the error message in case it's being called from a larger script which calls many other helper scripts.

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • it seems like the output of this code is always "script failed". I tried to make some modifications about the output still not that right. – cchi Oct 06 '19 at 20:01
  • I updated it to examine `$1` instead of a global `$var`. You still need to call it correctly (something like `check_parameter "$@"`). – tripleee Oct 07 '19 at 06:13
  • good call on redirecting messages to `stderr`. @cchi If this is for a class, make sure you can explain what `>&2` is doing and why it's there, bu it's definitely good to do in this situation. – Z4-tier Oct 08 '19 at 15:49