WelcomeWelcome | FAQFAQ | DownloadsDownloads | WikiWiki

Author Topic: script/ash - string length with Umlaut - and - read without trailing newline  (Read 4508 times)

Offline deetee

  • WikiUser
  • *
  • Posts: 34
Hi all!

Actually I have two questions (hopefully allowed in one task) regarding shell scripts for ash:

Question 1:
As I am a german TC user I installed a german keymap (de-latin1.kmap) with kmaps to use special characters (Umlaute) like "äöüß".
Unfortunately TC seems to use two bytes per Umlaut to store it in a string - so calculating the length of a string shows to high values.
Code: (ash) [Select]
string="jklö"
echo $string
echo ${#string}
So in this example the output is "jklö" and "5".
Does anybody know a solution to count the number of characters and not bytes (to show "4" in this example)?

Question 2:
I try to read a string at the bottom (last) line of my screen (with "read $STRING"). Unfortunately ending the input (pressing enter) causes a newline (scroll) and spoils the screen - which I want to prevent.
Does anybody know a solution for ash to prevent the trailing newline of read?

TIA deetee



Offline theYinYeti

  • Full Member
  • ***
  • Posts: 177
    • YetI web site
1/ TC’s default shell is busybox sh. This shell cannot handle multi-byte characters, such as ß, «, ÿ… (anything not ASCII when using UTF-8). For your purpose, you would have to change of shell to bash for example. See here:
http://forum.tinycorelinux.net/index.php/topic,15559.0.html
Code: [Select]
tc@tinycore:~$ test=bépo
tc@tinycore:~$ echo $test
bépo
tc@tinycore:~$ echo ${#test}
4

Online Rich

  • TinyCore Moderator
  • Hero Member
  • *****
  • Posts: 6966
Hi deetee
I copied and pasted your example into a file and got this result:
Code: [Select]
tc@box:~$ ls -l `which sh`
lrwxrwxrwx 1 root root 7 Nov 16  2011 /bin/sh -> busybox
tc@box:~$ ./z
jklö
4
tc@box:~$

Offline theYinYeti

  • Full Member
  • ***
  • Posts: 177
    • YetI web site
Rich, I think you’re using an ISO-8859-* encoding, such as de_DE, whereas deetee is probably using an UTF-8 encoding, such as de_DE.utf8

Offline gerald_clark

  • TinyCore Moderator
  • Hero Member
  • *****
  • Posts: 4254
For question #2
1. Your read is incorrect.   'read STRING' not 'read $STRING'.
2. Your CR on entry takes you to the next line.  That cannot be avoided.
You can user cursor movement character sequences to move up, but if you want to be able use the last line for display and input without
scrolling you should write a program that uses ncurses.

Offline theYinYeti

  • Full Member
  • ***
  • Posts: 177
    • YetI web site
2/ As gerald_clark said, what you want is not natively possible with the shell (with ncurses, maybe…). But you can create the feature ;-) I wrote this quickly with bash; I don’t know how portable it is to another shell:
Code: [Select]
function readchars() {
  local var=
  local tmp=     
  read -s -n 1 tmp
  while [ -n "$tmp" ]; do
    printf "$tmp"
    var="$var$tmp"
    read -s -n 1 tmp
  done
  eval $1=\""$(sed 's#["$]#\\\0#g' <<<"$var")"\"
}
Now use “readchars your_var” instead of “read your_var” and you’re done. The main problem is that the backspace key is not handled :-( Adapt to your needs…

[edit: last line in the function changed to actually change the given variable instead of just echo’ing the value]
« Last Edit: June 20, 2013, 07:05:18 AM by theYinYeti »

Offline gerald_clark

  • TinyCore Moderator
  • Hero Member
  • *****
  • Posts: 4254
To change it a bit so it looks more like read:

function readchars() {
  local var=
  local tmp=     
  read -n 1 tmp
  while [ -n "$tmp" ]; do
    printf "$tmp"
    var="$var$tmp"
    read -n 1 tmp
  done
}

#And to test
echo -ne "My Prompt -> "
RESULT=$(readchars)
echo " RESULT=$RESULT"

Offline deetee

  • WikiUser
  • *
  • Posts: 34
Hi all!

Thanks for your efforts and enlightenment.

@ Rich and theYinYeti:
It's strange, that your system shows the length of "jklö" as 4. To prevent troubles with UTF etc. (like theYinYeti suggested) I started CORE-TC (core.gz and vmlinuz) only (no kmaps and de-latin1.kmap) and run:
Code: (ash) [Select]
#! /bin/busybox ash
string="jklö"
echo $string
echo ${#string}
My outputs are still "jklö" and "5". Maybe the "ö" you copied from your browser is another "ö" than TC stored in my script?
To change to bash is not an option for me because I would like to write a script for core-TC (ash).
Is there a (simple) possibility to count such special characters in a string to substract it from the calculated length?


@ theYinYeti and gerald_clark:
I still considered to bypass the newline of read with single character read, but loosing the whole editing functionality of read seemed worse in relation to an annoying screen for a second. Although my solution wouldn't be as smart as yours. As ash doesn't support "<<<"-operations I concentrated to gerald_clark's version (without silent character reading).
To test your script how it behaves at the last line I extended it with escape sequences (input at last line - in my case 48 - and output at line 12):
Code: (ash) [Select]
#! /bin/busybox ash
CSI=$'x1b['

readchars(){
 local var=
 local tmp=
 read -n 1 tmp
 while [ -n "$tmp" ]; do
  printf "$tmp"
  var="$var$tmp"
  read -n 1 tmp
 done
}

echo -n "${CSI}48;5H" # substitute 48 with your last line number
echo -n "input: "
RESULT=$(readchars)
echo -n "${CSI}12;5H"
echo -n "output: $RESULT"
read -s -n 1 dummy
Unfortunately there still is a scrolling form feed after input and before output. Why?

TIA deetee

Offline theYinYeti

  • Full Member
  • ***
  • Posts: 177
    • YetI web site
You cannot avoid the line feed without silencing the read command. Here’s another version without the “<<<”, and that returns the value instead of setting a variable:
Code: [Select]
function readchars() {
  local var=
  local tmp=     
  read -s -n 1 tmp
  while [ -n "$tmp" ]; do
    printf "$tmp"
    var="$var$tmp"
    read -s -n 1 tmp
  done
  echo "$var"
}

test_variable="$(readchars)"

Offline deetee

  • WikiUser
  • *
  • Posts: 34
Hello theYinYeti!

Thanks for the enhancement.
Your script works fine - regarding the trailing newline.
But unfortunately someone can't see the Input now.

deetee

Offline theYinYeti

  • Full Member
  • ***
  • Posts: 177
    • YetI web site
Strange. Maybe printf does not exist with ash… Then try and change “printf” with “echo -n” instead.