2

I want to find the length of all my arguments passed to a script. If I do this: echo ${#1} I see the length of my first argument, and if I do this: echo $* I see all my arguments separated by spaces. So, why doesn't it work to do this: echo ${#*}? Instead this show me the number of arguments passed, as if it was echo $#.

Is there a way to echo the total length without writing the value of $* to a new variable ($allargs=$*) and then checking the length of the new variable (echo ${#allargs})?

Adriano_Pinaffo
  • 1,429
  • 4
  • 23
  • 46
  • Possible duplicate of [Check number of arguments passed to a Bash script](http://stackoverflow.com/questions/18568706/check-number-of-arguments-passed-to-a-bash-script) – Vadim Landa Apr 23 '17 at 17:45
  • 3
    @VadimLanda, I don't want to know the number of arguments passed. I want to know the total length of all the arguments combined. For me, it really doesn't matter how many were passed. – Adriano_Pinaffo Apr 23 '17 at 17:47
  • Is there a reason you can't save to a variable? – 123 Apr 23 '17 at 18:09
  • @123, no particular reason. It's just that I read in an article that it was possible but I couldn't make it work. – Adriano_Pinaffo Apr 23 '17 at 18:44
  • What's the article, pretty sure it's not possible. – 123 Apr 23 '17 at 18:59
  • 1
    `expr length "$*"`, but `expr` is no bash builtin. – Cyrus Apr 23 '17 at 19:10
  • @123, it's [here](http://www.linuxmagazine.com.br/images/uploads/pdf_aberto/LM07_shellscript7.pdf) on second page, where it says `# Centralizando a mensagem na tela Coluna=$(((Colunas - ${#*}) / 2))` Sorry it's in Portuguese but the code is there. – Adriano_Pinaffo Apr 23 '17 at 22:16
  • @Adriano_epifas is that not getting the number of args though, as `coluna`(column) would make me assume it is. – 123 Apr 24 '17 at 10:32
  • The article does say: "To avoid this annoyance, replace $1 by $*, that, as we know, is the list of all parameters. The line 8 would becocome as this ```# Centralizando a mensagem na tela Coluna=`$(((Colunas - ${#*}) / 2))` ```" –  Apr 24 '17 at 19:44
  • That is just wrong. Try this: `set -- one two t33; echo "<$*> ${#*}"`. the expansion `${#*}` gives the *count* of parameters, not the length of all the parameters. –  Apr 24 '17 at 19:44
  • @123, it should not be the number of arguments because the author is trying to get the number of chars in all the strings so he can get the number of columns on the terminal, then dived by 2 then subtract the size of $*, that way he can write something on the center of the screen. Well, maybe he forgot, who knows... thank you. – Adriano_Pinaffo Apr 25 '17 at 03:10
  • Thanks @sorontar, I think the author made a mistake then... I will save the content of $* to a variable than get the size of it with #. – Adriano_Pinaffo Apr 25 '17 at 03:12

2 Answers2

1

Sum the length of the arguments:

#!/bin/bash

declare -i length             # set integer attribute

for i in "${@}"; do length+=${#i}; done
echo $length
Cyrus
  • 84,225
  • 14
  • 89
  • 153
  • Thank you for the answer. But I wanted to avoid too much unnecessary coding. As I mentioned, I could save the value of $* to a variable and read its length. Besides, using your for loop I would be losing the spaces between each argument. – Adriano_Pinaffo Apr 23 '17 at 18:47
1

Well, yes, the simplest method is:

$ IFS=''; a=$*; echo "${#a}"

Yes, there is no way to avoid a variable ($a) as the variable (parameter) is needed to be able to perform a "parameter expansion" (${#…}).

That, above, measure the length (in UNICODE code points in bash) of the strings in $@.
Use LC_ALL=C to count bytes.

If you need to place "an space" between each string (assuming the first character of IFS is an space, as it is by default):

$ a=$*; echo "${#a}"

Or, to be explicit:

$ IFS=' '; a=$*; echo "${#a}"

That, of course, change the value of $IFS. There are two ways to avoid that:

A subshell

$ ( IFS=' '; a=$*; echo "${#a}" )

A delay with eval:

$ IFS=' ' eval 'a=$*'; echo "${#a}"

For byte counting:

$ ( LC_ALL=C; IFS=' '; a=$*; echo "${#a}" )
$ LC_ALL=C IFS=' ' eval 'a=$*'; echo "${#a}"

Yes, yes, eval is safe in this case.

And no, arithmetic tricks will not make the answer simple:

$ set --  one two t33; a=$*; echo "$((${#a}-$#+1))"
9

Fail with an empty "$@":

$ set --             ; a=$*; echo "$((${#a}-$#+1))"
1
  • Thank you for this answer. I think it's the closest one to what I wanted, and still you showed a lot of options, I'm ticking it as the the correct answer. – Adriano_Pinaffo Apr 25 '17 at 03:14