Kate
Kate

Reputation: 83

How to loop through a range of characters in a bash script using ASCII values?

I am trying to write a bash script which will read two letter variables (startletter/stopletter) and after that I need to print from the start letter to the stop letter with a for or something else. How can I do that?

I tried to do

#! /bin/bash 

echo "give start letter" 
read start 
echo "give stop letter" read stop 

But none of the for constructs work

#for value in {a..z} 
#for value in {$start..$stop} 
#for (( i=$start; i<=$stop; i++)) do echo "Letter: $c" done

Upvotes: 2

Views: 2906

Answers (2)

kvantour
kvantour

Reputation: 26511

In case you feel adventurous and want to use zsh instead of bash, you can use the following:

  • For zsh versions below 5.0.7 you can use the BRACE_CCL option:

(snip man zshall) If a brace expression matches none of the above forms, it is left unchanged, unless the option BRACE_CCL (an abbreviation for 'brace character class') is set. In that case, it is expanded to a list of the individual characters between the braces sorted into the order of the characters in the ASCII character set (multibyte characters are not currently handled). The syntax is similar to a [...] expression in filename generation: - is treated specially to denote a range of characters, but ^ or ! as the first character is treated normally. For example, {abcdef0-9} expands to 16 words 0 1 2 3 4 5 6 7 8 9 a b c d e f.

#!/usr/bin/env zsh

setopt brace_ccl
echo "give start letter" 
read cstart 
echo "give stop letter"
read cstop

for char in {${cstart}-${cstop}}; do echo $char; done
  • For zsh versions from 5.0.7 onwards you can use the default brace expansion :

An expression of the form {c1..c2}, where c1 and c2 are single characters (which may be multibyte characters), is expanded to every character in the range from c1 to c2 in whatever character sequence is used internally. For characters with code points below 128 this is US ASCII (this is the only case most users will need). If any intervening character is not printable, appropriate quotation is used to render it printable. If the character sequence is reversed, the output is in reverse order, e.g. {d..a} is substituted as d c b a.

#!/usr/bin/env zsh

echo "give start letter" 
read cstart 
echo "give stop letter"
read cstop

for char in {${cstart}..${cend}; do echo $char; done

More information on zsh can be found here and the quick reference

Upvotes: 2

Inian
Inian

Reputation: 85800

This question is very well explained in BashFAQ/071 How do I convert an ASCII character to its decimal (or hexadecimal) value and back?

# POSIX
# chr() - converts decimal value to its ASCII character representation
# ord() - converts ASCII character to its decimal value

chr () {
  local val
  [ "$1" -lt 256 ] || return 1
  printf -v val %o "$1"; printf "\\$val "
  # That one requires bash 3.1 or above.
}

ord() {
  # POSIX
  LC_CTYPE=C printf %d "'$1"
}

Re-using them for your requirement, a proper script would be written as

read -p "Input two variables: " startLetter stopLetter
[[ -z "$startLetter" || -z "$stopLetter" ]] && { printf 'one of the inputs is empty\n' >&2 ; }

asciiStart=$(ord "$startLetter") 
asciiStop=$(ord "$stopLetter") 

for ((i=asciiStart; i<=asciiStop; i++)); do
    chr "$i"
done    

Would print the letters as expected.


Adding it to community-wiki since this is also a cross-site duplicate from Unix.SE - Bash script to get ASCII values for alphabet

Upvotes: 2

Related Questions