2

I looked through some of the posted threads and none of them cover my query.

I have a simple line of code below which prints all the ASCII characters:

echo {' '..'~'} 

I want to be able to use a variable to substitute this array like below

list="{' '..'~'}" 

and then do the following

echo $(print ${list}) 

To clarify what I am trying to do:

passwordLength="2" for (( i = 0; i < $passwordLength; i++ )) do # concatenate random characters samplePasswordRegex="$samplePasswordRegex{' '..'~'}" done echo $^samplePasswordRegex 

2 Answers 2

1

I was using a method that jumped through hoops using some printf nonsense in order to put the result of the brace expansion into an array, I removed it from the answer because list=( {' '..~} ), as in ilkkachu's answer would Just Work; this is an alternative (worse) method.


If I understood correctly:

for c in {' '..~}; do list+=($c); done 

Some notes:

  • There's no need to quote ~ in the brace expansion;
  • Technically what's printed and stored is just a subset of ASCII (it excludes non-printable characters).
% for c in {' '..~}; do list+=($c); done % printf '%d\n' ${#list[@]} 95 % printf '%c' "${list[1]}" | xxd 00000000: 20 % printf '%c' "${list[2]}" | xxd 00000000: 21 ! % printf '%c' "${list[3]}" | xxd 00000000: 22 " % print ${list} ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ 
1

Brace expansion like {' '..'~'} results in a list. To assign a list to a variable, use a list assignment: list=( … ) where can consist of multiple words.

list=( {' '..'~'} ) 

(The spaces inside the parentheses aren't necessary, but they arguably make this a little more readable.)

This makes list an array variable. After this assignment, $list expands to the list of elements of the array. More precisely, $list expands to the list of non-empty elements, and you need something like $list[@] or "${(@)list}" to get all the elements; but here it doesn't matter since there are no empty elements.


That will not help you to generate a password, however. Zsh built-in constructs are not a secure way to generate a password because zsh does not have a secure random generator. ($RANDOM is not good enough: it uses a non-cryptographic strength pseudorandom generator seeded by a predictable seed.)

To generate a password, you can extract bytes from /dev/urandom. That is a secure random generator. Use tr to remove the byte values you don't want (unprintable or otherwise undesirable characters), and head -c to count the desired number of bytes. For example, the following snippet generates a password of 8 ASCII characters:

setopt pipe_fail err_exit password=$(</dev/urandom tr -dc ' -~' | head -c 8) 

Note further that this is a poor choice of password characters. Some characters are hard to tell visually (if the password starts or ends with a space, will you be able to tell?). Some characters are hard to type on some keyboards. And special characters are hard to memorize. Using special characters in passwords is counterproductive. (And yes, that's still good advice). If you want a password you can memorize, use the “correct horse battery staple” method, i.e. pick (short) words at random. If the password doesn't need to be memorable, pick random lowercase letters. 4 random lowercase letters has almost the same strength as 3 random printable ASCII characters (log(95) / log(26) ≈ 4/3), so if you were happy with 8 printable ASCII characters, use 12 lowercase letters instead for a slightly stronger password that's much easier to read and enter.

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.