0

I'm just starting to learn shell, and I felt really puzzled when I got a syntax error in this simple code :

str="Hello world!"
echo $(expr length "$str")

But this code can work on Ubantu actually. Is it because my bash version is outdated? Or is it a problem with the MacOS system?

I have updated my bash version, now it is GNU bash 5.1.16, but this problem still exists. I'm really confused right now.

  • Are you _sure_ you are using Bash? – KamilCuk Apr 04 '22 at 06:24
  • I would go with @KamilCuk as Apple switched to zsh as a default with Catalina. – Arne Burmeister Apr 04 '22 at 06:32
  • 1
    As an aside, that's a [useless use of `echo`](https://www.iki.fi/era/unix/award.html#echo); `expr` by itself already prints its output to standard output, so capturing it in a command substitution so you can `echo` it is just an unnecessary and slightly inefficient complication. – tripleee Apr 04 '22 at 06:33
  • Zsh is the _default_ shell for new users on MacOS now, but the OP says they have installed a newer version of Bash on their own, so I would take their word for it. – tripleee Apr 04 '22 at 06:33
  • Yeah, because the tutorial I went through was using bash, I change the default shell in the preferences setting of the Terminal. – StaY_Hungry Apr 04 '22 at 07:57
  • But actually I found several shells in my computer, aren't you? – StaY_Hungry Apr 04 '22 at 07:59
  • The minimal expectation is to find a POSIX shell. Many systems for interactive use have more complex shells with better interactive features. On Linux, you would generally expect to find Bash as the default shell, but other systems have other traditions and offerings. – tripleee Apr 04 '22 at 08:07

1 Answers1

3

expr on MacOS does not accept the argument length. The man page contains this rather oblique passage:

According to the POSIX standard, the use of string arguments length, substr, index, or match produces undefined results. In this version of expr, these arguments are treated just as their respective string values.

In other words, expr length simply returns length and expr length "$str" is a syntax error because expr only accepts a single argument.

This isn't a problem really, because Bash scripts should basically never need to use expr at all. Bash has built-in facilities which replace more or less all of the legacy expr logic.

To get the length of a string in Bash, try

${#str}

For more, probably start with the parameter expansions in Bash.

expr is an OS utility which is independent of your shell, so it doesn't really make any difference which version of Bash you are using, or in fact whether you are using a shell at all.

If you find yourself in a situation where you need to get a string's length portably in a POSIX sh / Bourne shell script, perhaps resort to Awk.

len=$(printf '%s\n' "$str" | awk '{ print(length($0)) }')

(This will print multiple numbers if str contains multiple lines. It's not hard to change it if you need to find the total length of a string with embedded newlines, but I'm guessing we don't need to go there.)

tripleee
  • 175,061
  • 34
  • 275
  • 318
  • Maybe it's worth noting that the OP could also install the [Gnu Coreutils](https://www.topbug.net/blog/2013/04/14/install-and-use-gnu-command-line-tools-in-mac-os-x/) on MacOS. – user1934428 Apr 04 '22 at 09:23