3

I have a bash script; the script is to generate a random number and have the user guess it.

printf 'Guess the number (1-10) : '
read -r n
randint=$(( ( RANDOM % 10 )  + 1 ))
if [ $n = $randint ];
then
echo "You Won !"
else
echo "Sorry, try again !"
fi

It works, but in the next script I have encoded this code into base64 and tried to run it using the following code.

exec="cHJpbnRmICdHdWVzcyB0aGUgbnVtYmVyICgxLTEwKSA6ICcKcmVhZCAtciBuCnJhbmRpbnQ9JCgoICggUkFORE9NICUgMTAgKSAgKyAxICkpCgppZiBbICRuID0gJHJhbmRpbnQgXTsKdGhlbgplY2hvICJZb3UgV29uICEiCmVsc2UKZWNobyAiU29ycnksIHRyeSBhZ2FpbiAhIgpmaQ=="
base64 -d <<< $exec | sh

It gives this error in a Cygwin Terminal:

Guess the number (1-10) : sh: line 4: [: too many arguments
Sorry, try again !

I tried an online compiler and it failed also:

sh: 5: [: =: unexpected operator

I don't know to fix this.

9
  • 3
    Always escape variables in if . and use -eq when compare numbers Commented Jan 12, 2022 at 13:17
  • 11
    First of all: sh and bash are not equivalent. Commented Jan 12, 2022 at 13:24
  • 2
    read is trying to read from the same stream that the script is being read from, I think... Commented Jan 12, 2022 at 13:26
  • 2
    bash <( base64 -d <<<string ) But I fail to see the point of the exercise.
    – Kusalananda
    Commented Jan 12, 2022 at 13:34
  • 2
    ... another perhaps more closely related example Piping a script with "read" to bash Commented Jan 12, 2022 at 13:45

1 Answer 1

11

Run it with set -x to see what the shell actually runs, the commands are shown in the lines starting with + :

+ printf 'Guess the number (1-10) : '
Guess the number (1-10) : + read -r n
+ '[' 'randint=$((' '(' RANDOM % 10 ')' + 1 '))' = ']'
bash: line 4: [: too many arguments
[...]

What's that in the test, inside [ ... ], the assignment randint=...(*)? It was supposed to be what read n gives. And it was supposed to ask the number from the user, but didn't?

Well, there's the thing, read reads from standard input, and in the pipeline base64 ... | bash the script that the shell runs also comes from standard input. So read dutifully reads the next line in the input stream, the one with randint=..., and puts it in the variable n...

(* $n is word-split to multiple arguments, of course, since $n was not quoted.)

You need to arrange for the script to come in from a different file descriptor, either by e.g. using process substitution to pass the script to the shell (in Bash/ksh/zsh):

bash <( base64 -d <<< "$exec" )

or by having read read from some other fd, e.g. directly from the terminal by redirecting the input to read from /dev/tty. Testing with an almost one-liner (the single-quoted string continues to the second line):

$ printf 'read -r -p "say something: " foo < /dev/tty; 
          echo "you entered: $foo"' | bash
say something: asdfsadf
you entered: asdfsadf

Then again, you might consider just passing input data as command line arguments, instead of interactively asking for it. Command line arguments are easier to script, and reading the terminal directly is also especially obnoxious, precisely because it prevents easily using a script to feed the program.

Note also that RANDOM isn't a standard shell feature, so you should probably run the script explicitly with bash (or ksh, or zsh), and not sh.

0

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .