Skip to main content
added 148 characters in body
Source Link
ilkkachu
  • 147.9k
  • 16
  • 268
  • 441

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 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, it's the one with randint=....

(* The string is word-split to multiple arguments, of course, sinceand puts it in the variable $nn was not quoted.)..

(* $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. In a smaller exampleTesting 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.

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, the assignment randint=...(*)? It was supposed to be what read n gives. And it was supposed to ask the number from the user? 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, it's the one with randint=....

(* The string 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. In a smaller example:

$ 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.

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.

added 170 characters in body
Source Link
ilkkachu
  • 147.9k
  • 16
  • 268
  • 441

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, the assignment randint=...(*)? It was supposed to be what read n gives. And it was supposed to ask the number from the user? 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, it's the one with randint=....

(* The string 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. In a smaller example:

$ 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.

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, the assignment randint=...(*)? It was supposed to be what read n gives. And it was supposed to ask the number from the user? 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, it's the one with randint=....

(* The string 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:

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. In a smaller example:

$ 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.

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, the assignment randint=...(*)? It was supposed to be what read n gives. And it was supposed to ask the number from the user? 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, it's the one with randint=....

(* The string 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. In a smaller example:

$ 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.

Source Link
ilkkachu
  • 147.9k
  • 16
  • 268
  • 441

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, the assignment randint=...(*)? It was supposed to be what read n gives. And it was supposed to ask the number from the user? 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, it's the one with randint=....

(* The string 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:

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. In a smaller example:

$ 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.