I want this function to return one random word if there aren't any command-line arguments.

I am modifying linuxconfig.org's random-word generator to run even when #$ -ne 1.

function random-word {
    if [ $# -eq 0 ] ;
        echo "I only take one argument, dummy"
        # previously was exit 0

    # Constants 

    # total number of non-random words available 
    non_random_words=`cat $ALL_NON_RANDOM_WORDS | wc -l` 

    # while loop to generate random words  
    # number of random generated words depends on supplied argument 
    while [ $X -lt "$1" ] 
    random_number=`od -N3 -An -i /dev/urandom | 
    awk -v f=0 -v r="$non_random_words" '{printf "%i\n", f + r * $1 / 16777216}'` 
    sed `echo $random_number`"q;d" $ALL_NON_RANDOM_WORDS 
      let "X = X + 1" 

The statement executes, but there's a bash error:

$ bob
I only take one argument, dummy
bash: [: : integer expression expected

How do I fix this so the bash error won't display?

closed as off-topic by Gilles, Braiam, jasonwryan, jordanm, cuonglm Jul 23 '14 at 7:08

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Questions describing a problem that can't be reproduced and seemingly went away on its own (or went away when a typo was fixed) are off-topic as they are unlikely to help future readers." – Gilles, Braiam, jasonwryan, jordanm, cuonglm
If this question can be reworded to fit the rules in the help center, please edit the question.

  • 3
    The error is further in your script, since it's display after the “dummy” message. – Gilles Jul 22 '14 at 23:50
  • 3
    Given what you've posted now: the value of x isn't what you think. What is it? I don't know, since you didn't post that part of the code. Stop wasting our time and post a working example. – Gilles Jul 23 '14 at 0:03
  • 2
    The code you posted still isn't complete (it's the start of a function definition) and the fragment here still doesn't exhibit the issue. As it stands, this question is not useful to anybody else, hence it should be closed. Let's stop here, shall we? – Gilles Jul 23 '14 at 0:15
  • 1
    @Gilles - you're completely wrong here. The most useful questions are the ones that demonstrate what not to do. This is an incredibly useful question. – mikeserv Jul 23 '14 at 0:23
  • 2
    @Gilles - see the answer? it's a great question. and the answer is very good. – mikeserv Jul 23 '14 at 0:25

while [ $X -lt "$1" ] is being evaluated even when there is no $1.

Move the rest of the code into an else block so this doesn't happen.

function random-word {
    # from linuxconfig.org 

    if [ $# -eq 0 ] 
        echo "I need an argument, dummy"
        # To be extra friendly, give them a random word.
        echo "Here's a random word:"
        random-word 1
        # Constants 


        sed `echo $random_number`"q;d" $ALL_NON_RANDOM_WORDS 
          let "X = X + 1" 
  • Also occurs if there is a $1, but it's not a number. – Patrick Jul 23 '14 at 5:32

You don't need an else block. And you don't need to fail if you receive more than one argument. You only need to fail if you don't get an argument and you can then just ignore everything else or quit if you don't get at least the one.

set -- "${1?ERR: Where\'s my argument?!?!}"

That statement does all of that. This does the same but also fails if the first argument is only the '' nullstring :

set -- "${1:?ERR: Where\'s my argument?!?!}"

Of course, if the point is to be a shell function called from an interactive shell, this might kill the interactive shell as well, so you can do:

(: "${1:?Where\'s my argument?}") || return && set -- "$1"

...which will handle that as well. But, in my opinion, a shell function should never affect an interactive shell unless absolutely necessary - like if it needs to alter a current shell variable or something. And so better than the above would be to declare the function as a subshell, like:

fn() (set -- "${1:?Where\'s my argument?}" && echo "$1")


Another way to do this is to accept all arguments and concatenate them - so all arguments are only treated as one in every case. You can do that like:

fn() (                              
    : "${1:?ERR: Where\'s my argument?}"
    set -- "$*" && echo "$1" 
fn '' ; fn here are a lot of arguments that will all be treated as one
sh: line 2: 1: ERR: Where's my argument?
here are a lot of arguments that will all be treated as one

I personally don't much like the sh: line 2: 1: bit that usually happens - at least not in interactive shells. I usually stick a CTRL+V CTRL+M in before ERR: so it does a return to the head of the line in a terminal and writes over that bit but still outputs the more useful info into a log. Like:

fn() (                              
    : "${1:?^MERR: Where\'s my argument?}"
    set -- "$*" && echo "$1" 
fn ; fn 2>&1 | cat -A
ERR: Where's my argument?
sh: line 2: 1: ^MERR: Where's my argument?$
  • I liked the ${1:^MERR: text} solution but it does not clear to end of line so if the text is less than the script: line#: error_string it will leave garbage out there – johnnyB Apr 5 '15 at 9:41
  • @johhnyb Do something with ^[[2K then maybe. It should be noted though that the output device might not be a terminal after all. You can check it like [ t 2 ] though. – mikeserv Apr 6 '15 at 2:57
  • Beautify! that works in most terminals which clears to end-of-line. so now the msg looks nicer. went from Account="${1?-Please provide account name}" to Account="${1?^M$PROGRAM: ERROR: Please specify account^[[K}"... the users does not have to see the line number the error occurred on. – johnnyB Apr 7 '15 at 21:17

Not the answer you're looking for? Browse other questions tagged or ask your own question.