0

I got a strange behavior when running a script with arguments that contains a command substitution. I would like to understand why is this behavior happening. The script is:

#!/bin/bash

# MAIL=$1
# USER=$2
PASSWORD=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w ${1:-20} | head -n 1);
echo "$PASSWORD"

Then I run: ./test.sh mail user, I get the error: fold: invalid number of columns: ‘mail’ and the Password is not generated.

If I don't pass an argument or I don't generate the password, it works fine.

Update (for understanding the behavior)

I think I've found out what is happening: When running a script with two arguments the $1 and $2 have the passed values. Example: ./test.sh arg1 arg2 have $1 -> arg1 and $2 -> arg2

When using a pipe inside a script, the original arguments are still passed and thus if you have two arguments as input you will have the piped output inserted into the third place $3.

  • $1 -> arg1
  • $2 -> arg2
  • $3 -> piped output So a working solution would be:
PASSWORD=$(cat /dev/urandom | tr -dc 'a-zA-Z0-9' | fold -w ${3:-20} | head -n 1);

but if you vary the input arguments, it will not work. Therefore the best solution is what @KamilCuk suggested:

PASSWORD=$(< /dev/urandom tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1);
Pulsar
  • 3
  • 3
  • I don't understand. What do you expect `fold -w mail` to do? Do you understand what `${1:-20}` does? – KamilCuk Feb 10 '21 at 10:12
  • I pipe "cat /dev/urandom and filter it to valid characters (tr -dc ...). fold should take the first 20 valid characters but not any argument I pass to the script (like "mail") 1. I'm not expecting at all to have "fold -w mail". 2. ${1:-20} takes the first 20 characters from the generated string – Pulsar Feb 10 '21 at 10:21
  • `${1:-20} takes the first 20 characters from the generated string` No. `fold` when passed a number of `20` takes the first 20 characters. When` $1` is `mail`, then it does `fold -w mail`, which is invaild. When `$1` is unset or empty, then `fold` is passed `20`. `I'm not expecting at all to have "fold -w mail"` Then do you understand what `${var:-something}` means? Add `set -x` to debug your scripts. – KamilCuk Feb 10 '21 at 10:27
  • Thank you, now I am a step further. With `${1:-something}` I am expecting the first argument that the pipe passes to it. It works if you just run `./test.sh` but it seems that the `$1` is replaced when I add an argument to the script like `./test.sh arg` right? – Pulsar Feb 10 '21 at 10:41
  • [shell parameter expansion](https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html). [bash positional parameters](https://www.gnu.org/software/bash/manual/html_node/Positional-Parameters.html). – KamilCuk Feb 10 '21 at 10:42

1 Answers1

0

If you do not wish to pass the first script argument to fold, then do not use $1 in it.

PASSWORD=$(< /dev/urandom tr -dc 'a-zA-Z0-9' | fold -w 20 | head -n 1);
#                                                      ^^ - pass the number, not $1
echo "$PASSWORD"
KamilCuk
  • 120,984
  • 8
  • 59
  • 111