bug-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: printf %n is not documented


From: Emanuele Torre
Subject: Re: printf %n is not documented
Date: Sat, 7 Jan 2023 17:14:48 +0100
User-agent: Mutt/2.2.9 (2022-11-12)

On Sat, Jan 07, 2023 at 03:00:58PM +0100, felix wrote:
>    strU8DiffLen0() { local _cLen=${#1} LC_ALL=C;return $((${#1}-_cLen));}

Do not use `return' like that.

`return' is used to make functions report an exit status: 0 for success,
non-zero for various kinds of failure, just like executable programs.

The exit status of a program can only be between 0 and 255, and should
only be between 0 and 125 because 126, 127, and values above 128 have special
meaning for the shell's $? special parameter.

Using `return' to return a value instead of reporting an error code, is
just stupid.

But, in your case, your code is just broken.

Since exit statuses can only ever be a number between 0 and 255, if the
value is above 255 (undocumented), `return' will return the value you
passed modulo 255. Definitely not what you want in your case.

  bash-5.1$ a () { return 2000; }; a; echo "$?"
  208
  bash-5.1$ a () { return -2; }; a; echo "$?"
  254
  bash-5.1$ a () { return -2; }; a; echo "$?"
  254
  bash-5.1$ a () { return 100000000; }; a; echo "$?"
  254
  bash-5.1$ a () { return 10020000000004001; }; a; echo "$?"
  161

Behaviour may vary in other shells, e.g. in dash, the same commands
result in:

  $ a () { return 2000; }; a; echo "$?"
  2000
  $ a () { return -2; }; a; echo "$?"
  dash: 2: return: Illegal number: -2
  $ a () { return 100000000; }; a; echo "$?"
  100000000
  $ a () { return 10020000000004001; }; a; echo "$?"
  dash: 4: return: Illegal number: 10020000000004001

To "return" a value, either use a non-local variable e.g.

  myfunction ()
  {
    local length=${#1} bytelength
    printf -v _ %s%n "$1" bytelength
    ret_myfunction=$(( lenght - bytelength ))
  }

  myfunction "$string1"
  something "$ret_myfunction"

  myotherfunction ()
  {
    local ret_myfunction len1 len2
    myfunction "$1"
    len1=$ret_myfunction
    myfunction "$2"
    len2=$ret_myfunction
    myfunction "$3"
    something "$(( len1 - len2 - ret_myfunction ))"
  }

Or output the result to stdout, and make the caller use command
substitution to read it.

  myfunction ()
  {
    local length=${#1} bytelength
    printf -v _ %s%n "$1" bytelength
    printf %s\\n "$(( lenght - bytelength ))"
  }

  something "$(myfunction "$ret_myfunction")"

Another less important note:
Using  return $((${#1}-_cLen))  is also problematic, because it is
incorrectly and unnecessarily IFS dependent. If IFS contains a number,
the function will break e.g. if the result of the expression is 103 and
IFS=0, that will run  return 1 3  throwing a shell error.
If you ever need to return a computed value from a function (rarely if
you are using `return' correctly instead of misusing it as you were
doing), you should use  return -- "$(( ${#1} - _cLen ))" .

Hope this helps.
 emanuele6



reply via email to

[Prev in Thread] Current Thread [Next in Thread]